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/ContactsManager.h"
8
9 #include "td/telegram/AuthManager.h"
10 #include "td/telegram/ConfigManager.h"
11 #include "td/telegram/ConfigShared.h"
12 #include "td/telegram/Dependencies.h"
13 #include "td/telegram/DeviceTokenManager.h"
14 #include "td/telegram/DialogInviteLink.h"
15 #include "td/telegram/DialogLocation.h"
16 #include "td/telegram/FileReferenceManager.h"
17 #include "td/telegram/files/FileManager.h"
18 #include "td/telegram/files/FileType.h"
19 #include "td/telegram/FolderId.h"
20 #include "td/telegram/Global.h"
21 #include "td/telegram/GroupCallManager.h"
22 #include "td/telegram/InlineQueriesManager.h"
23 #include "td/telegram/InputGroupCallId.h"
24 #include "td/telegram/LinkManager.h"
25 #include "td/telegram/logevent/LogEvent.h"
26 #include "td/telegram/logevent/LogEventHelper.h"
27 #include "td/telegram/MessageSender.h"
28 #include "td/telegram/MessagesManager.h"
29 #include "td/telegram/MessageTtlSetting.h"
30 #include "td/telegram/misc.h"
31 #include "td/telegram/net/NetQuery.h"
32 #include "td/telegram/NotificationManager.h"
33 #include "td/telegram/PasswordManager.h"
34 #include "td/telegram/Photo.h"
35 #include "td/telegram/Photo.hpp"
36 #include "td/telegram/SecretChatLayer.h"
37 #include "td/telegram/SecretChatsManager.h"
38 #include "td/telegram/ServerMessageId.h"
39 #include "td/telegram/StickerSetId.hpp"
40 #include "td/telegram/StickersManager.h"
41 #include "td/telegram/Td.h"
42 #include "td/telegram/TdDb.h"
43 #include "td/telegram/TdParameters.h"
44 #include "td/telegram/telegram_api.hpp"
45 #include "td/telegram/UpdatesManager.h"
46 #include "td/telegram/Version.h"
47
48 #include "td/db/binlog/BinlogEvent.h"
49 #include "td/db/binlog/BinlogHelper.h"
50 #include "td/db/SqliteKeyValue.h"
51 #include "td/db/SqliteKeyValueAsync.h"
52
53 #include "td/actor/PromiseFuture.h"
54 #include "td/actor/SleepActor.h"
55
56 #include "td/utils/algorithm.h"
57 #include "td/utils/buffer.h"
58 #include "td/utils/format.h"
59 #include "td/utils/logging.h"
60 #include "td/utils/misc.h"
61 #include "td/utils/Random.h"
62 #include "td/utils/Slice.h"
63 #include "td/utils/SliceBuilder.h"
64 #include "td/utils/StringBuilder.h"
65 #include "td/utils/Time.h"
66 #include "td/utils/tl_helpers.h"
67 #include "td/utils/utf8.h"
68
69 #include <algorithm>
70 #include <limits>
71 #include <tuple>
72 #include <utility>
73
74 namespace td {
75
76 class DismissSuggestionQuery final : public Td::ResultHandler {
77 Promise<Unit> promise_;
78 DialogId dialog_id_;
79
80 public:
DismissSuggestionQuery(Promise<Unit> && promise)81 explicit DismissSuggestionQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
82 }
83
send(SuggestedAction action)84 void send(SuggestedAction action) {
85 dialog_id_ = action.dialog_id_;
86 auto input_peer = td_->messages_manager_->get_input_peer(dialog_id_, AccessRights::Read);
87 CHECK(input_peer != nullptr);
88
89 send_query(G()->net_query_creator().create(
90 telegram_api::help_dismissSuggestion(std::move(input_peer), action.get_suggested_action_str())));
91 }
92
on_result(BufferSlice packet)93 void on_result(BufferSlice packet) final {
94 auto result_ptr = fetch_result<telegram_api::help_dismissSuggestion>(packet);
95 if (result_ptr.is_error()) {
96 return on_error(result_ptr.move_as_error());
97 }
98
99 promise_.set_value(Unit());
100 }
101
on_error(Status status)102 void on_error(Status status) final {
103 td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "DismissSuggestionQuery");
104 promise_.set_error(std::move(status));
105 }
106 };
107
108 class GetContactsQuery final : public Td::ResultHandler {
109 public:
send(int64 hash)110 void send(int64 hash) {
111 send_query(G()->net_query_creator().create(telegram_api::contacts_getContacts(hash)));
112 }
113
on_result(BufferSlice packet)114 void on_result(BufferSlice packet) final {
115 auto result_ptr = fetch_result<telegram_api::contacts_getContacts>(packet);
116 if (result_ptr.is_error()) {
117 return on_error(result_ptr.move_as_error());
118 }
119
120 auto ptr = result_ptr.move_as_ok();
121 LOG(INFO) << "Receive result for GetContactsQuery: " << to_string(ptr);
122 td_->contacts_manager_->on_get_contacts(std::move(ptr));
123 }
124
on_error(Status status)125 void on_error(Status status) final {
126 td_->contacts_manager_->on_get_contacts_failed(std::move(status));
127 td_->updates_manager_->get_difference("GetContactsQuery");
128 }
129 };
130
131 class GetContactsStatusesQuery final : public Td::ResultHandler {
132 public:
send()133 void send() {
134 send_query(G()->net_query_creator().create(telegram_api::contacts_getStatuses()));
135 }
136
on_result(BufferSlice packet)137 void on_result(BufferSlice packet) final {
138 auto result_ptr = fetch_result<telegram_api::contacts_getStatuses>(packet);
139 if (result_ptr.is_error()) {
140 return on_error(result_ptr.move_as_error());
141 }
142
143 td_->contacts_manager_->on_get_contacts_statuses(result_ptr.move_as_ok());
144 }
145
on_error(Status status)146 void on_error(Status status) final {
147 if (!G()->is_expected_error(status)) {
148 LOG(ERROR) << "Receive error for GetContactsStatusesQuery: " << status;
149 }
150 }
151 };
152
153 class AddContactQuery final : public Td::ResultHandler {
154 Promise<Unit> promise_;
155 UserId user_id_;
156
157 public:
AddContactQuery(Promise<Unit> && promise)158 explicit AddContactQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
159 }
160
send(UserId user_id,tl_object_ptr<telegram_api::InputUser> && input_user,const Contact & contact,bool share_phone_number)161 void send(UserId user_id, tl_object_ptr<telegram_api::InputUser> &&input_user, const Contact &contact,
162 bool share_phone_number) {
163 user_id_ = user_id;
164 int32 flags = 0;
165 if (share_phone_number) {
166 flags |= telegram_api::contacts_addContact::ADD_PHONE_PRIVACY_EXCEPTION_MASK;
167 }
168 send_query(G()->net_query_creator().create(
169 telegram_api::contacts_addContact(flags, false /*ignored*/, std::move(input_user), contact.get_first_name(),
170 contact.get_last_name(), contact.get_phone_number())));
171 }
172
on_result(BufferSlice packet)173 void on_result(BufferSlice packet) final {
174 auto result_ptr = fetch_result<telegram_api::contacts_addContact>(packet);
175 if (result_ptr.is_error()) {
176 return on_error(result_ptr.move_as_error());
177 }
178
179 auto ptr = result_ptr.move_as_ok();
180 LOG(INFO) << "Receive result for AddContactQuery: " << to_string(ptr);
181 td_->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_));
182 }
183
on_error(Status status)184 void on_error(Status status) final {
185 promise_.set_error(std::move(status));
186 td_->contacts_manager_->reload_contacts(true);
187 td_->messages_manager_->reget_dialog_action_bar(DialogId(user_id_), "AddContactQuery");
188 }
189 };
190
191 class AcceptContactQuery final : public Td::ResultHandler {
192 Promise<Unit> promise_;
193 UserId user_id_;
194
195 public:
AcceptContactQuery(Promise<Unit> && promise)196 explicit AcceptContactQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
197 }
198
send(UserId user_id,tl_object_ptr<telegram_api::InputUser> && input_user)199 void send(UserId user_id, tl_object_ptr<telegram_api::InputUser> &&input_user) {
200 user_id_ = user_id;
201 send_query(G()->net_query_creator().create(telegram_api::contacts_acceptContact(std::move(input_user))));
202 }
203
on_result(BufferSlice packet)204 void on_result(BufferSlice packet) final {
205 auto result_ptr = fetch_result<telegram_api::contacts_acceptContact>(packet);
206 if (result_ptr.is_error()) {
207 return on_error(result_ptr.move_as_error());
208 }
209
210 auto ptr = result_ptr.move_as_ok();
211 LOG(INFO) << "Receive result for AcceptContactQuery: " << to_string(ptr);
212 td_->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_));
213 }
214
on_error(Status status)215 void on_error(Status status) final {
216 promise_.set_error(std::move(status));
217 td_->contacts_manager_->reload_contacts(true);
218 td_->messages_manager_->reget_dialog_action_bar(DialogId(user_id_), "AcceptContactQuery");
219 }
220 };
221
222 class ImportContactsQuery final : public Td::ResultHandler {
223 int64 random_id_ = 0;
224 size_t sent_size_ = 0;
225
226 public:
send(vector<tl_object_ptr<telegram_api::inputPhoneContact>> && input_phone_contacts,int64 random_id)227 void send(vector<tl_object_ptr<telegram_api::inputPhoneContact>> &&input_phone_contacts, int64 random_id) {
228 random_id_ = random_id;
229 sent_size_ = input_phone_contacts.size();
230 send_query(G()->net_query_creator().create(telegram_api::contacts_importContacts(std::move(input_phone_contacts))));
231 }
232
on_result(BufferSlice packet)233 void on_result(BufferSlice packet) final {
234 auto result_ptr = fetch_result<telegram_api::contacts_importContacts>(packet);
235 if (result_ptr.is_error()) {
236 return on_error(result_ptr.move_as_error());
237 }
238
239 auto ptr = result_ptr.move_as_ok();
240 LOG(INFO) << "Receive result for ImportContactsQuery: " << to_string(ptr);
241 if (sent_size_ == ptr->retry_contacts_.size()) {
242 return on_error(Status::Error(429, "Too Many Requests: retry after 3600"));
243 }
244 td_->contacts_manager_->on_imported_contacts(random_id_, std::move(ptr));
245 }
246
on_error(Status status)247 void on_error(Status status) final {
248 td_->contacts_manager_->on_imported_contacts(random_id_, std::move(status));
249 }
250 };
251
252 class DeleteContactsQuery final : public Td::ResultHandler {
253 Promise<Unit> promise_;
254
255 public:
DeleteContactsQuery(Promise<Unit> && promise)256 explicit DeleteContactsQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
257 }
258
send(vector<tl_object_ptr<telegram_api::InputUser>> && input_users)259 void send(vector<tl_object_ptr<telegram_api::InputUser>> &&input_users) {
260 send_query(G()->net_query_creator().create(telegram_api::contacts_deleteContacts(std::move(input_users))));
261 }
262
on_result(BufferSlice packet)263 void on_result(BufferSlice packet) final {
264 auto result_ptr = fetch_result<telegram_api::contacts_deleteContacts>(packet);
265 if (result_ptr.is_error()) {
266 return on_error(result_ptr.move_as_error());
267 }
268
269 auto ptr = result_ptr.move_as_ok();
270 LOG(INFO) << "Receive result for DeleteContactsQuery: " << to_string(ptr);
271 td_->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_));
272 }
273
on_error(Status status)274 void on_error(Status status) final {
275 promise_.set_error(std::move(status));
276 td_->contacts_manager_->reload_contacts(true);
277 }
278 };
279
280 class DeleteContactsByPhoneNumberQuery final : public Td::ResultHandler {
281 Promise<Unit> promise_;
282 vector<UserId> user_ids_;
283
284 public:
DeleteContactsByPhoneNumberQuery(Promise<Unit> && promise)285 explicit DeleteContactsByPhoneNumberQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
286 }
287
send(vector<string> && user_phone_numbers,vector<UserId> && user_ids)288 void send(vector<string> &&user_phone_numbers, vector<UserId> &&user_ids) {
289 if (user_phone_numbers.empty()) {
290 return promise_.set_value(Unit());
291 }
292 user_ids_ = std::move(user_ids);
293 send_query(G()->net_query_creator().create(telegram_api::contacts_deleteByPhones(std::move(user_phone_numbers))));
294 }
295
on_result(BufferSlice packet)296 void on_result(BufferSlice packet) final {
297 auto result_ptr = fetch_result<telegram_api::contacts_deleteByPhones>(packet);
298 if (result_ptr.is_error()) {
299 return on_error(result_ptr.move_as_error());
300 }
301
302 bool result = result_ptr.ok();
303 if (!result) {
304 return on_error(Status::Error(500, "Some contacts can't be deleted"));
305 }
306
307 td_->contacts_manager_->on_deleted_contacts(user_ids_);
308 promise_.set_value(Unit());
309 }
310
on_error(Status status)311 void on_error(Status status) final {
312 promise_.set_error(std::move(status));
313 td_->contacts_manager_->reload_contacts(true);
314 }
315 };
316
317 class ResetContactsQuery final : public Td::ResultHandler {
318 Promise<Unit> promise_;
319
320 public:
ResetContactsQuery(Promise<Unit> && promise)321 explicit ResetContactsQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
322 }
323
send()324 void send() {
325 send_query(G()->net_query_creator().create(telegram_api::contacts_resetSaved()));
326 }
327
on_result(BufferSlice packet)328 void on_result(BufferSlice packet) final {
329 auto result_ptr = fetch_result<telegram_api::contacts_resetSaved>(packet);
330 if (result_ptr.is_error()) {
331 return on_error(result_ptr.move_as_error());
332 }
333
334 bool result = result_ptr.ok();
335 if (!result) {
336 LOG(ERROR) << "Failed to delete imported contacts";
337 td_->contacts_manager_->reload_contacts(true);
338 } else {
339 td_->contacts_manager_->on_update_contacts_reset();
340 }
341
342 promise_.set_value(Unit());
343 }
344
on_error(Status status)345 void on_error(Status status) final {
346 promise_.set_error(std::move(status));
347 td_->contacts_manager_->reload_contacts(true);
348 }
349 };
350
351 class SearchDialogsNearbyQuery final : public Td::ResultHandler {
352 Promise<tl_object_ptr<telegram_api::Updates>> promise_;
353
354 public:
SearchDialogsNearbyQuery(Promise<tl_object_ptr<telegram_api::Updates>> && promise)355 explicit SearchDialogsNearbyQuery(Promise<tl_object_ptr<telegram_api::Updates>> &&promise)
356 : promise_(std::move(promise)) {
357 }
358
send(const Location & location,bool from_background,int32 expire_date)359 void send(const Location &location, bool from_background, int32 expire_date) {
360 int32 flags = 0;
361 if (from_background) {
362 flags |= telegram_api::contacts_getLocated::BACKGROUND_MASK;
363 }
364 if (expire_date != -1) {
365 flags |= telegram_api::contacts_getLocated::SELF_EXPIRES_MASK;
366 }
367 send_query(G()->net_query_creator().create(
368 telegram_api::contacts_getLocated(flags, false /*ignored*/, location.get_input_geo_point(), expire_date)));
369 }
370
on_result(BufferSlice packet)371 void on_result(BufferSlice packet) final {
372 auto result_ptr = fetch_result<telegram_api::contacts_getLocated>(packet);
373 if (result_ptr.is_error()) {
374 return on_error(result_ptr.move_as_error());
375 }
376
377 promise_.set_value(result_ptr.move_as_ok());
378 }
379
on_error(Status status)380 void on_error(Status status) final {
381 promise_.set_error(std::move(status));
382 }
383 };
384
385 class UploadProfilePhotoQuery final : public Td::ResultHandler {
386 Promise<Unit> promise_;
387 FileId file_id_;
388
389 public:
UploadProfilePhotoQuery(Promise<Unit> && promise)390 explicit UploadProfilePhotoQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
391 }
392
send(FileId file_id,tl_object_ptr<telegram_api::InputFile> && input_file,bool is_animation,double main_frame_timestamp)393 void send(FileId file_id, tl_object_ptr<telegram_api::InputFile> &&input_file, bool is_animation,
394 double main_frame_timestamp) {
395 CHECK(input_file != nullptr);
396 CHECK(file_id.is_valid());
397
398 file_id_ = file_id;
399
400 int32 flags = 0;
401 tl_object_ptr<telegram_api::InputFile> photo_input_file;
402 tl_object_ptr<telegram_api::InputFile> video_input_file;
403 if (is_animation) {
404 flags |= telegram_api::photos_uploadProfilePhoto::VIDEO_MASK;
405 video_input_file = std::move(input_file);
406
407 if (main_frame_timestamp != 0.0) {
408 flags |= telegram_api::photos_uploadProfilePhoto::VIDEO_START_TS_MASK;
409 }
410 } else {
411 flags |= telegram_api::photos_uploadProfilePhoto::FILE_MASK;
412 photo_input_file = std::move(input_file);
413 }
414 send_query(G()->net_query_creator().create(telegram_api::photos_uploadProfilePhoto(
415 flags, std::move(photo_input_file), std::move(video_input_file), main_frame_timestamp)));
416 }
417
on_result(BufferSlice packet)418 void on_result(BufferSlice packet) final {
419 auto result_ptr = fetch_result<telegram_api::photos_uploadProfilePhoto>(packet);
420 if (result_ptr.is_error()) {
421 return on_error(result_ptr.move_as_error());
422 }
423
424 td_->contacts_manager_->on_set_profile_photo(result_ptr.move_as_ok(), 0);
425
426 td_->file_manager_->delete_partial_remote_location(file_id_);
427
428 promise_.set_value(Unit());
429 }
430
on_error(Status status)431 void on_error(Status status) final {
432 promise_.set_error(std::move(status));
433 td_->file_manager_->delete_partial_remote_location(file_id_);
434 td_->updates_manager_->get_difference("UploadProfilePhotoQuery");
435 }
436 };
437
438 class UpdateProfilePhotoQuery final : public Td::ResultHandler {
439 Promise<Unit> promise_;
440 FileId file_id_;
441 int64 old_photo_id_;
442 string file_reference_;
443
444 public:
UpdateProfilePhotoQuery(Promise<Unit> && promise)445 explicit UpdateProfilePhotoQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
446 }
447
send(FileId file_id,int64 old_photo_id,tl_object_ptr<telegram_api::InputPhoto> && input_photo)448 void send(FileId file_id, int64 old_photo_id, tl_object_ptr<telegram_api::InputPhoto> &&input_photo) {
449 CHECK(input_photo != nullptr);
450 file_id_ = file_id;
451 old_photo_id_ = old_photo_id;
452 file_reference_ = FileManager::extract_file_reference(input_photo);
453 send_query(G()->net_query_creator().create(telegram_api::photos_updateProfilePhoto(std::move(input_photo))));
454 }
455
on_result(BufferSlice packet)456 void on_result(BufferSlice packet) final {
457 auto result_ptr = fetch_result<telegram_api::photos_updateProfilePhoto>(packet);
458 if (result_ptr.is_error()) {
459 return on_error(result_ptr.move_as_error());
460 }
461
462 td_->contacts_manager_->on_set_profile_photo(result_ptr.move_as_ok(), old_photo_id_);
463
464 promise_.set_value(Unit());
465 }
466
on_error(Status status)467 void on_error(Status status) final {
468 if (!td_->auth_manager_->is_bot() && FileReferenceManager::is_file_reference_error(status)) {
469 if (file_id_.is_valid()) {
470 VLOG(file_references) << "Receive " << status << " for " << file_id_;
471 td_->file_manager_->delete_file_reference(file_id_, file_reference_);
472 td_->file_reference_manager_->repair_file_reference(
473 file_id_, PromiseCreator::lambda([file_id = file_id_, old_photo_id = old_photo_id_,
474 promise = std::move(promise_)](Result<Unit> result) mutable {
475 if (result.is_error()) {
476 return promise.set_error(Status::Error(400, "Can't find the photo"));
477 }
478
479 send_closure(G()->contacts_manager(), &ContactsManager::send_update_profile_photo_query, file_id,
480 old_photo_id, std::move(promise));
481 }));
482 return;
483 } else {
484 LOG(ERROR) << "Receive file reference error, but file_id = " << file_id_;
485 }
486 }
487
488 promise_.set_error(std::move(status));
489 }
490 };
491
492 class DeleteProfilePhotoQuery final : public Td::ResultHandler {
493 Promise<Unit> promise_;
494 int64 profile_photo_id_;
495
496 public:
DeleteProfilePhotoQuery(Promise<Unit> && promise)497 explicit DeleteProfilePhotoQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
498 }
499
send(int64 profile_photo_id)500 void send(int64 profile_photo_id) {
501 profile_photo_id_ = profile_photo_id;
502 vector<tl_object_ptr<telegram_api::InputPhoto>> input_photo_ids;
503 input_photo_ids.push_back(make_tl_object<telegram_api::inputPhoto>(profile_photo_id, 0, BufferSlice()));
504 send_query(G()->net_query_creator().create(telegram_api::photos_deletePhotos(std::move(input_photo_ids))));
505 }
506
on_result(BufferSlice packet)507 void on_result(BufferSlice packet) final {
508 auto result_ptr = fetch_result<telegram_api::photos_deletePhotos>(packet);
509 if (result_ptr.is_error()) {
510 return on_error(result_ptr.move_as_error());
511 }
512
513 auto result = result_ptr.move_as_ok();
514 LOG(INFO) << "Receive result for DeleteProfilePhotoQuery: " << format::as_array(result);
515 if (result.size() != 1u) {
516 LOG(WARNING) << "Photo can't be deleted";
517 return on_error(Status::Error(400, "Photo can't be deleted"));
518 }
519
520 td_->contacts_manager_->on_delete_profile_photo(profile_photo_id_, std::move(promise_));
521 }
522
on_error(Status status)523 void on_error(Status status) final {
524 promise_.set_error(std::move(status));
525 }
526 };
527
528 class UpdateProfileQuery final : public Td::ResultHandler {
529 Promise<Unit> promise_;
530 int32 flags_;
531 string first_name_;
532 string last_name_;
533 string about_;
534
535 public:
UpdateProfileQuery(Promise<Unit> && promise)536 explicit UpdateProfileQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
537 }
538
send(int32 flags,const string & first_name,const string & last_name,const string & about)539 void send(int32 flags, const string &first_name, const string &last_name, const string &about) {
540 flags_ = flags;
541 first_name_ = first_name;
542 last_name_ = last_name;
543 about_ = about;
544 send_query(
545 G()->net_query_creator().create(telegram_api::account_updateProfile(flags, first_name, last_name, about)));
546 }
547
on_result(BufferSlice packet)548 void on_result(BufferSlice packet) final {
549 auto result_ptr = fetch_result<telegram_api::account_updateProfile>(packet);
550 if (result_ptr.is_error()) {
551 return on_error(result_ptr.move_as_error());
552 }
553
554 LOG(DEBUG) << "Receive result for UpdateProfileQuery: " << to_string(result_ptr.ok());
555 td_->contacts_manager_->on_get_user(result_ptr.move_as_ok(), "UpdateProfileQuery");
556 td_->contacts_manager_->on_update_profile_success(flags_, first_name_, last_name_, about_);
557
558 promise_.set_value(Unit());
559 }
560
on_error(Status status)561 void on_error(Status status) final {
562 promise_.set_error(std::move(status));
563 }
564 };
565
566 class CheckUsernameQuery final : public Td::ResultHandler {
567 Promise<bool> promise_;
568
569 public:
CheckUsernameQuery(Promise<bool> && promise)570 explicit CheckUsernameQuery(Promise<bool> &&promise) : promise_(std::move(promise)) {
571 }
572
send(const string & username)573 void send(const string &username) {
574 send_query(G()->net_query_creator().create(telegram_api::account_checkUsername(username)));
575 }
576
on_result(BufferSlice packet)577 void on_result(BufferSlice packet) final {
578 auto result_ptr = fetch_result<telegram_api::account_checkUsername>(packet);
579 if (result_ptr.is_error()) {
580 return on_error(result_ptr.move_as_error());
581 }
582
583 promise_.set_value(result_ptr.move_as_ok());
584 }
585
on_error(Status status)586 void on_error(Status status) final {
587 promise_.set_error(std::move(status));
588 }
589 };
590
591 class UpdateUsernameQuery final : public Td::ResultHandler {
592 Promise<Unit> promise_;
593
594 public:
UpdateUsernameQuery(Promise<Unit> && promise)595 explicit UpdateUsernameQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
596 }
597
send(const string & username)598 void send(const string &username) {
599 send_query(G()->net_query_creator().create(telegram_api::account_updateUsername(username)));
600 }
601
on_result(BufferSlice packet)602 void on_result(BufferSlice packet) final {
603 auto result_ptr = fetch_result<telegram_api::account_updateUsername>(packet);
604 if (result_ptr.is_error()) {
605 return on_error(result_ptr.move_as_error());
606 }
607
608 LOG(DEBUG) << "Receive result for UpdateUsernameQuery: " << to_string(result_ptr.ok());
609 td_->contacts_manager_->on_get_user(result_ptr.move_as_ok(), "UpdateUsernameQuery");
610 promise_.set_value(Unit());
611 }
612
on_error(Status status)613 void on_error(Status status) final {
614 if (status.message() == "USERNAME_NOT_MODIFIED" && !td_->auth_manager_->is_bot()) {
615 promise_.set_value(Unit());
616 return;
617 }
618 promise_.set_error(std::move(status));
619 }
620 };
621
622 class CheckChannelUsernameQuery final : public Td::ResultHandler {
623 Promise<bool> promise_;
624 ChannelId channel_id_;
625 string username_;
626
627 public:
CheckChannelUsernameQuery(Promise<bool> && promise)628 explicit CheckChannelUsernameQuery(Promise<bool> &&promise) : promise_(std::move(promise)) {
629 }
630
send(ChannelId channel_id,const string & username)631 void send(ChannelId channel_id, const string &username) {
632 channel_id_ = channel_id;
633 tl_object_ptr<telegram_api::InputChannel> input_channel;
634 if (channel_id.is_valid()) {
635 input_channel = td_->contacts_manager_->get_input_channel(channel_id);
636 } else {
637 input_channel = make_tl_object<telegram_api::inputChannelEmpty>();
638 }
639 CHECK(input_channel != nullptr);
640 send_query(
641 G()->net_query_creator().create(telegram_api::channels_checkUsername(std::move(input_channel), username)));
642 }
643
on_result(BufferSlice packet)644 void on_result(BufferSlice packet) final {
645 auto result_ptr = fetch_result<telegram_api::channels_checkUsername>(packet);
646 if (result_ptr.is_error()) {
647 return on_error(result_ptr.move_as_error());
648 }
649
650 promise_.set_value(result_ptr.move_as_ok());
651 }
652
on_error(Status status)653 void on_error(Status status) final {
654 if (channel_id_.is_valid()) {
655 td_->contacts_manager_->on_get_channel_error(channel_id_, status, "CheckChannelUsernameQuery");
656 }
657 promise_.set_error(std::move(status));
658 }
659 };
660
661 class UpdateChannelUsernameQuery final : public Td::ResultHandler {
662 Promise<Unit> promise_;
663 ChannelId channel_id_;
664 string username_;
665
666 public:
UpdateChannelUsernameQuery(Promise<Unit> && promise)667 explicit UpdateChannelUsernameQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
668 }
669
send(ChannelId channel_id,const string & username)670 void send(ChannelId channel_id, const string &username) {
671 channel_id_ = channel_id;
672 username_ = username;
673 auto input_channel = td_->contacts_manager_->get_input_channel(channel_id);
674 CHECK(input_channel != nullptr);
675 send_query(
676 G()->net_query_creator().create(telegram_api::channels_updateUsername(std::move(input_channel), username)));
677 }
678
on_result(BufferSlice packet)679 void on_result(BufferSlice packet) final {
680 auto result_ptr = fetch_result<telegram_api::channels_updateUsername>(packet);
681 if (result_ptr.is_error()) {
682 return on_error(result_ptr.move_as_error());
683 }
684
685 bool result = result_ptr.ok();
686 LOG(DEBUG) << "Receive result for UpdateChannelUsernameQuery: " << result;
687 if (!result) {
688 return on_error(Status::Error(500, "Supergroup username is not updated"));
689 }
690
691 td_->contacts_manager_->on_update_channel_username(channel_id_, std::move(username_));
692 promise_.set_value(Unit());
693 }
694
on_error(Status status)695 void on_error(Status status) final {
696 if (status.message() == "USERNAME_NOT_MODIFIED" || status.message() == "CHAT_NOT_MODIFIED") {
697 td_->contacts_manager_->on_update_channel_username(channel_id_, std::move(username_));
698 if (!td_->auth_manager_->is_bot()) {
699 promise_.set_value(Unit());
700 return;
701 }
702 } else {
703 td_->contacts_manager_->on_get_channel_error(channel_id_, status, "UpdateChannelUsernameQuery");
704 }
705 promise_.set_error(std::move(status));
706 }
707 };
708
709 class SetChannelStickerSetQuery final : public Td::ResultHandler {
710 Promise<Unit> promise_;
711 ChannelId channel_id_;
712 StickerSetId sticker_set_id_;
713
714 public:
SetChannelStickerSetQuery(Promise<Unit> && promise)715 explicit SetChannelStickerSetQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
716 }
717
send(ChannelId channel_id,StickerSetId sticker_set_id,telegram_api::object_ptr<telegram_api::InputStickerSet> && input_sticker_set)718 void send(ChannelId channel_id, StickerSetId sticker_set_id,
719 telegram_api::object_ptr<telegram_api::InputStickerSet> &&input_sticker_set) {
720 channel_id_ = channel_id;
721 sticker_set_id_ = sticker_set_id;
722 auto input_channel = td_->contacts_manager_->get_input_channel(channel_id);
723 CHECK(input_channel != nullptr);
724 send_query(G()->net_query_creator().create(
725 telegram_api::channels_setStickers(std::move(input_channel), std::move(input_sticker_set))));
726 }
727
on_result(BufferSlice packet)728 void on_result(BufferSlice packet) final {
729 auto result_ptr = fetch_result<telegram_api::channels_setStickers>(packet);
730 if (result_ptr.is_error()) {
731 return on_error(result_ptr.move_as_error());
732 }
733
734 bool result = result_ptr.ok();
735 LOG(DEBUG) << "Receive result for SetChannelStickerSetQuery: " << result;
736 if (!result) {
737 return on_error(Status::Error(500, "Supergroup sticker set not updated"));
738 }
739
740 td_->contacts_manager_->on_update_channel_sticker_set(channel_id_, sticker_set_id_);
741 promise_.set_value(Unit());
742 }
743
on_error(Status status)744 void on_error(Status status) final {
745 if (status.message() == "CHAT_NOT_MODIFIED") {
746 td_->contacts_manager_->on_update_channel_sticker_set(channel_id_, sticker_set_id_);
747 if (!td_->auth_manager_->is_bot()) {
748 promise_.set_value(Unit());
749 return;
750 }
751 } else {
752 td_->contacts_manager_->on_get_channel_error(channel_id_, status, "SetChannelStickerSetQuery");
753 }
754 promise_.set_error(std::move(status));
755 }
756 };
757
758 class ToggleChannelSignaturesQuery final : public Td::ResultHandler {
759 Promise<Unit> promise_;
760 ChannelId channel_id_;
761
762 public:
ToggleChannelSignaturesQuery(Promise<Unit> && promise)763 explicit ToggleChannelSignaturesQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
764 }
765
send(ChannelId channel_id,bool sign_messages)766 void send(ChannelId channel_id, bool sign_messages) {
767 channel_id_ = channel_id;
768 auto input_channel = td_->contacts_manager_->get_input_channel(channel_id);
769 CHECK(input_channel != nullptr);
770 send_query(G()->net_query_creator().create(
771 telegram_api::channels_toggleSignatures(std::move(input_channel), sign_messages)));
772 }
773
on_result(BufferSlice packet)774 void on_result(BufferSlice packet) final {
775 auto result_ptr = fetch_result<telegram_api::channels_toggleSignatures>(packet);
776 if (result_ptr.is_error()) {
777 return on_error(result_ptr.move_as_error());
778 }
779
780 auto ptr = result_ptr.move_as_ok();
781 LOG(INFO) << "Receive result for ToggleChannelSignaturesQuery: " << to_string(ptr);
782 td_->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_));
783 }
784
on_error(Status status)785 void on_error(Status status) final {
786 if (status.message() == "CHAT_NOT_MODIFIED") {
787 if (!td_->auth_manager_->is_bot()) {
788 promise_.set_value(Unit());
789 return;
790 }
791 } else {
792 td_->contacts_manager_->on_get_channel_error(channel_id_, status, "ToggleChannelSignaturesQuery");
793 }
794 promise_.set_error(std::move(status));
795 }
796 };
797
798 class TogglePrehistoryHiddenQuery final : public Td::ResultHandler {
799 Promise<Unit> promise_;
800 ChannelId channel_id_;
801 bool is_all_history_available_;
802
803 public:
TogglePrehistoryHiddenQuery(Promise<Unit> && promise)804 explicit TogglePrehistoryHiddenQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
805 }
806
send(ChannelId channel_id,bool is_all_history_available)807 void send(ChannelId channel_id, bool is_all_history_available) {
808 channel_id_ = channel_id;
809 is_all_history_available_ = is_all_history_available;
810
811 auto input_channel = td_->contacts_manager_->get_input_channel(channel_id);
812 CHECK(input_channel != nullptr);
813 send_query(G()->net_query_creator().create(
814 telegram_api::channels_togglePreHistoryHidden(std::move(input_channel), !is_all_history_available)));
815 }
816
on_result(BufferSlice packet)817 void on_result(BufferSlice packet) final {
818 auto result_ptr = fetch_result<telegram_api::channels_togglePreHistoryHidden>(packet);
819 if (result_ptr.is_error()) {
820 return on_error(result_ptr.move_as_error());
821 }
822
823 auto ptr = result_ptr.move_as_ok();
824 LOG(INFO) << "Receive result for TogglePrehistoryHiddenQuery: " << to_string(ptr);
825
826 td_->updates_manager_->on_get_updates(
827 std::move(ptr),
828 PromiseCreator::lambda([actor_id = G()->contacts_manager(), promise = std::move(promise_),
829 channel_id = channel_id_,
830 is_all_history_available = is_all_history_available_](Unit result) mutable {
831 send_closure(actor_id, &ContactsManager::on_update_channel_is_all_history_available, channel_id,
832 is_all_history_available, std::move(promise));
833 }));
834 }
835
on_error(Status status)836 void on_error(Status status) final {
837 if (status.message() == "CHAT_NOT_MODIFIED") {
838 if (!td_->auth_manager_->is_bot()) {
839 promise_.set_value(Unit());
840 return;
841 }
842 } else {
843 td_->contacts_manager_->on_get_channel_error(channel_id_, status, "TogglePrehistoryHiddenQuery");
844 }
845 promise_.set_error(std::move(status));
846 }
847 };
848
849 class ConvertToGigagroupQuery final : public Td::ResultHandler {
850 Promise<Unit> promise_;
851 ChannelId channel_id_;
852
853 public:
ConvertToGigagroupQuery(Promise<Unit> && promise)854 explicit ConvertToGigagroupQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
855 }
856
send(ChannelId channel_id)857 void send(ChannelId channel_id) {
858 channel_id_ = channel_id;
859
860 auto input_channel = td_->contacts_manager_->get_input_channel(channel_id);
861 CHECK(input_channel != nullptr);
862 send_query(G()->net_query_creator().create(telegram_api::channels_convertToGigagroup(std::move(input_channel))));
863 }
864
on_result(BufferSlice packet)865 void on_result(BufferSlice packet) final {
866 auto result_ptr = fetch_result<telegram_api::channels_convertToGigagroup>(packet);
867 if (result_ptr.is_error()) {
868 return on_error(result_ptr.move_as_error());
869 }
870
871 auto ptr = result_ptr.move_as_ok();
872 LOG(INFO) << "Receive result for ConvertToGigagroupQuery: " << to_string(ptr);
873
874 td_->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_));
875 }
876
on_error(Status status)877 void on_error(Status status) final {
878 if (status.message() == "CHAT_NOT_MODIFIED") {
879 promise_.set_value(Unit());
880 return;
881 } else {
882 td_->contacts_manager_->on_get_channel_error(channel_id_, status, "ConvertToGigagroupQuery");
883 }
884 promise_.set_error(std::move(status));
885 }
886 };
887
888 class EditChatAboutQuery final : public Td::ResultHandler {
889 Promise<Unit> promise_;
890 DialogId dialog_id_;
891 string about_;
892
on_success()893 void on_success() {
894 switch (dialog_id_.get_type()) {
895 case DialogType::Chat:
896 return td_->contacts_manager_->on_update_chat_description(dialog_id_.get_chat_id(), std::move(about_));
897 case DialogType::Channel:
898 return td_->contacts_manager_->on_update_channel_description(dialog_id_.get_channel_id(), std::move(about_));
899 case DialogType::User:
900 case DialogType::SecretChat:
901 case DialogType::None:
902 UNREACHABLE();
903 }
904 }
905
906 public:
EditChatAboutQuery(Promise<Unit> && promise)907 explicit EditChatAboutQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
908 }
909
send(DialogId dialog_id,const string & about)910 void send(DialogId dialog_id, const string &about) {
911 dialog_id_ = dialog_id;
912 about_ = about;
913 auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Write);
914 if (input_peer == nullptr) {
915 return on_error(Status::Error(400, "Can't access the chat"));
916 }
917 send_query(G()->net_query_creator().create(telegram_api::messages_editChatAbout(std::move(input_peer), about)));
918 }
919
on_result(BufferSlice packet)920 void on_result(BufferSlice packet) final {
921 auto result_ptr = fetch_result<telegram_api::messages_editChatAbout>(packet);
922 if (result_ptr.is_error()) {
923 return on_error(result_ptr.move_as_error());
924 }
925
926 bool result = result_ptr.ok();
927 LOG(DEBUG) << "Receive result for EditChatAboutQuery: " << result;
928 if (!result) {
929 return on_error(Status::Error(500, "Chat description is not updated"));
930 }
931
932 on_success();
933 promise_.set_value(Unit());
934 }
935
on_error(Status status)936 void on_error(Status status) final {
937 if (status.message() == "CHAT_ABOUT_NOT_MODIFIED" || status.message() == "CHAT_NOT_MODIFIED") {
938 on_success();
939 if (!td_->auth_manager_->is_bot()) {
940 promise_.set_value(Unit());
941 return;
942 }
943 } else {
944 td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "EditChatAboutQuery");
945 }
946 promise_.set_error(std::move(status));
947 }
948 };
949
950 class SetDiscussionGroupQuery final : public Td::ResultHandler {
951 Promise<Unit> promise_;
952 ChannelId broadcast_channel_id_;
953 ChannelId group_channel_id_;
954
955 public:
SetDiscussionGroupQuery(Promise<Unit> && promise)956 explicit SetDiscussionGroupQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
957 }
958
send(ChannelId broadcast_channel_id,telegram_api::object_ptr<telegram_api::InputChannel> broadcast_input_channel,ChannelId group_channel_id,telegram_api::object_ptr<telegram_api::InputChannel> group_input_channel)959 void send(ChannelId broadcast_channel_id,
960 telegram_api::object_ptr<telegram_api::InputChannel> broadcast_input_channel, ChannelId group_channel_id,
961 telegram_api::object_ptr<telegram_api::InputChannel> group_input_channel) {
962 broadcast_channel_id_ = broadcast_channel_id;
963 group_channel_id_ = group_channel_id;
964 send_query(G()->net_query_creator().create(
965 telegram_api::channels_setDiscussionGroup(std::move(broadcast_input_channel), std::move(group_input_channel))));
966 }
967
on_result(BufferSlice packet)968 void on_result(BufferSlice packet) final {
969 auto result_ptr = fetch_result<telegram_api::channels_setDiscussionGroup>(packet);
970 if (result_ptr.is_error()) {
971 return on_error(result_ptr.move_as_error());
972 }
973
974 bool result = result_ptr.move_as_ok();
975 LOG_IF(INFO, !result) << "Set discussion group has failed";
976
977 td_->contacts_manager_->on_update_channel_linked_channel_id(broadcast_channel_id_, group_channel_id_);
978 promise_.set_value(Unit());
979 }
980
on_error(Status status)981 void on_error(Status status) final {
982 if (status.message() == "LINK_NOT_MODIFIED") {
983 return promise_.set_value(Unit());
984 }
985 promise_.set_error(std::move(status));
986 }
987 };
988
989 class EditLocationQuery final : public Td::ResultHandler {
990 Promise<Unit> promise_;
991 ChannelId channel_id_;
992 DialogLocation location_;
993
994 public:
EditLocationQuery(Promise<Unit> && promise)995 explicit EditLocationQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
996 }
997
send(ChannelId channel_id,const DialogLocation & location)998 void send(ChannelId channel_id, const DialogLocation &location) {
999 channel_id_ = channel_id;
1000 location_ = location;
1001
1002 auto input_channel = td_->contacts_manager_->get_input_channel(channel_id);
1003 CHECK(input_channel != nullptr);
1004
1005 send_query(G()->net_query_creator().create(telegram_api::channels_editLocation(
1006 std::move(input_channel), location_.get_input_geo_point(), location_.get_address())));
1007 }
1008
on_result(BufferSlice packet)1009 void on_result(BufferSlice packet) final {
1010 auto result_ptr = fetch_result<telegram_api::channels_editLocation>(packet);
1011 if (result_ptr.is_error()) {
1012 return on_error(result_ptr.move_as_error());
1013 }
1014
1015 bool result = result_ptr.move_as_ok();
1016 LOG_IF(INFO, !result) << "Edit chat location has failed";
1017
1018 td_->contacts_manager_->on_update_channel_location(channel_id_, location_);
1019 promise_.set_value(Unit());
1020 }
1021
on_error(Status status)1022 void on_error(Status status) final {
1023 td_->contacts_manager_->on_get_channel_error(channel_id_, status, "EditLocationQuery");
1024 promise_.set_error(std::move(status));
1025 }
1026 };
1027
1028 class ToggleSlowModeQuery final : public Td::ResultHandler {
1029 Promise<Unit> promise_;
1030 ChannelId channel_id_;
1031 int32 slow_mode_delay_ = 0;
1032
1033 public:
ToggleSlowModeQuery(Promise<Unit> && promise)1034 explicit ToggleSlowModeQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
1035 }
1036
send(ChannelId channel_id,int32 slow_mode_delay)1037 void send(ChannelId channel_id, int32 slow_mode_delay) {
1038 channel_id_ = channel_id;
1039 slow_mode_delay_ = slow_mode_delay;
1040
1041 auto input_channel = td_->contacts_manager_->get_input_channel(channel_id);
1042 CHECK(input_channel != nullptr);
1043
1044 send_query(G()->net_query_creator().create(
1045 telegram_api::channels_toggleSlowMode(std::move(input_channel), slow_mode_delay)));
1046 }
1047
on_result(BufferSlice packet)1048 void on_result(BufferSlice packet) final {
1049 auto result_ptr = fetch_result<telegram_api::channels_toggleSlowMode>(packet);
1050 if (result_ptr.is_error()) {
1051 return on_error(result_ptr.move_as_error());
1052 }
1053
1054 auto ptr = result_ptr.move_as_ok();
1055 LOG(INFO) << "Receive result for ToggleSlowModeQuery: " << to_string(ptr);
1056
1057 td_->updates_manager_->on_get_updates(
1058 std::move(ptr),
1059 PromiseCreator::lambda([actor_id = G()->contacts_manager(), promise = std::move(promise_),
1060 channel_id = channel_id_, slow_mode_delay = slow_mode_delay_](Unit result) mutable {
1061 send_closure(actor_id, &ContactsManager::on_update_channel_slow_mode_delay, channel_id, slow_mode_delay,
1062 std::move(promise));
1063 }));
1064 }
1065
on_error(Status status)1066 void on_error(Status status) final {
1067 if (status.message() == "CHAT_NOT_MODIFIED") {
1068 td_->contacts_manager_->on_update_channel_slow_mode_delay(channel_id_, slow_mode_delay_, Promise<Unit>());
1069 if (!td_->auth_manager_->is_bot()) {
1070 promise_.set_value(Unit());
1071 return;
1072 }
1073 } else {
1074 td_->contacts_manager_->on_get_channel_error(channel_id_, status, "ToggleSlowModeQuery");
1075 }
1076 promise_.set_error(std::move(status));
1077 }
1078 };
1079
1080 class ReportChannelSpamQuery final : public Td::ResultHandler {
1081 Promise<Unit> promise_;
1082 ChannelId channel_id_;
1083
1084 public:
ReportChannelSpamQuery(Promise<Unit> && promise)1085 explicit ReportChannelSpamQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
1086 }
1087
send(ChannelId channel_id,DialogId sender_dialog_id,const vector<MessageId> & message_ids)1088 void send(ChannelId channel_id, DialogId sender_dialog_id, const vector<MessageId> &message_ids) {
1089 channel_id_ = channel_id;
1090
1091 auto input_channel = td_->contacts_manager_->get_input_channel(channel_id);
1092 CHECK(input_channel != nullptr);
1093
1094 auto input_peer = td_->messages_manager_->get_input_peer(sender_dialog_id, AccessRights::Know);
1095 CHECK(input_peer != nullptr);
1096
1097 send_query(G()->net_query_creator().create(telegram_api::channels_reportSpam(
1098 std::move(input_channel), std::move(input_peer), MessagesManager::get_server_message_ids(message_ids))));
1099 }
1100
on_result(BufferSlice packet)1101 void on_result(BufferSlice packet) final {
1102 auto result_ptr = fetch_result<telegram_api::channels_reportSpam>(packet);
1103 if (result_ptr.is_error()) {
1104 return on_error(result_ptr.move_as_error());
1105 }
1106
1107 bool result = result_ptr.move_as_ok();
1108 LOG_IF(INFO, !result) << "Report spam has failed in " << channel_id_;
1109
1110 promise_.set_value(Unit());
1111 }
1112
on_error(Status status)1113 void on_error(Status status) final {
1114 // td_->contacts_manager_->on_get_channel_error(channel_id_, status, "ReportChannelSpamQuery");
1115 promise_.set_error(std::move(status));
1116 }
1117 };
1118
1119 class DeleteChatQuery final : public Td::ResultHandler {
1120 Promise<Unit> promise_;
1121
1122 public:
DeleteChatQuery(Promise<Unit> && promise)1123 explicit DeleteChatQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
1124 }
1125
send(ChatId chat_id)1126 void send(ChatId chat_id) {
1127 send_query(G()->net_query_creator().create(telegram_api::messages_deleteChat(chat_id.get())));
1128 }
1129
on_result(BufferSlice packet)1130 void on_result(BufferSlice packet) final {
1131 auto result_ptr = fetch_result<telegram_api::messages_deleteChat>(packet);
1132 if (result_ptr.is_error()) {
1133 return on_error(result_ptr.move_as_error());
1134 }
1135
1136 LOG(INFO) << "Receive result for DeleteChatQuery: " << result_ptr.ok();
1137 td_->updates_manager_->get_difference("DeleteChatQuery");
1138 td_->updates_manager_->on_get_updates(make_tl_object<telegram_api::updates>(), std::move(promise_));
1139 }
1140
on_error(Status status)1141 void on_error(Status status) final {
1142 promise_.set_error(std::move(status));
1143 }
1144 };
1145
1146 class DeleteChannelQuery final : public Td::ResultHandler {
1147 Promise<Unit> promise_;
1148 ChannelId channel_id_;
1149
1150 public:
DeleteChannelQuery(Promise<Unit> && promise)1151 explicit DeleteChannelQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
1152 }
1153
send(ChannelId channel_id)1154 void send(ChannelId channel_id) {
1155 channel_id_ = channel_id;
1156 auto input_channel = td_->contacts_manager_->get_input_channel(channel_id);
1157 CHECK(input_channel != nullptr);
1158 send_query(G()->net_query_creator().create(telegram_api::channels_deleteChannel(std::move(input_channel))));
1159 }
1160
on_result(BufferSlice packet)1161 void on_result(BufferSlice packet) final {
1162 auto result_ptr = fetch_result<telegram_api::channels_deleteChannel>(packet);
1163 if (result_ptr.is_error()) {
1164 return on_error(result_ptr.move_as_error());
1165 }
1166
1167 auto ptr = result_ptr.move_as_ok();
1168 LOG(INFO) << "Receive result for DeleteChannelQuery: " << to_string(ptr);
1169 td_->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_));
1170 }
1171
on_error(Status status)1172 void on_error(Status status) final {
1173 td_->contacts_manager_->on_get_channel_error(channel_id_, status, "DeleteChannelQuery");
1174 promise_.set_error(std::move(status));
1175 }
1176 };
1177
1178 class AddChatUserQuery final : public Td::ResultHandler {
1179 Promise<Unit> promise_;
1180
1181 public:
AddChatUserQuery(Promise<Unit> && promise)1182 explicit AddChatUserQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
1183 }
1184
send(ChatId chat_id,tl_object_ptr<telegram_api::InputUser> && input_user,int32 forward_limit)1185 void send(ChatId chat_id, tl_object_ptr<telegram_api::InputUser> &&input_user, int32 forward_limit) {
1186 send_query(G()->net_query_creator().create(
1187 telegram_api::messages_addChatUser(chat_id.get(), std::move(input_user), forward_limit)));
1188 }
1189
on_result(BufferSlice packet)1190 void on_result(BufferSlice packet) final {
1191 auto result_ptr = fetch_result<telegram_api::messages_addChatUser>(packet);
1192 if (result_ptr.is_error()) {
1193 return on_error(result_ptr.move_as_error());
1194 }
1195
1196 auto ptr = result_ptr.move_as_ok();
1197 LOG(INFO) << "Receive result for AddChatUserQuery: " << to_string(ptr);
1198 td_->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_));
1199 }
1200
on_error(Status status)1201 void on_error(Status status) final {
1202 promise_.set_error(std::move(status));
1203 td_->updates_manager_->get_difference("AddChatUserQuery");
1204 }
1205 };
1206
1207 class EditChatAdminQuery final : public Td::ResultHandler {
1208 Promise<Unit> promise_;
1209 ChatId chat_id_;
1210
1211 public:
EditChatAdminQuery(Promise<Unit> && promise)1212 explicit EditChatAdminQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
1213 }
1214
send(ChatId chat_id,tl_object_ptr<telegram_api::InputUser> && input_user,bool is_administrator)1215 void send(ChatId chat_id, tl_object_ptr<telegram_api::InputUser> &&input_user, bool is_administrator) {
1216 chat_id_ = chat_id;
1217 send_query(G()->net_query_creator().create(
1218 telegram_api::messages_editChatAdmin(chat_id.get(), std::move(input_user), is_administrator)));
1219 }
1220
on_result(BufferSlice packet)1221 void on_result(BufferSlice packet) final {
1222 auto result_ptr = fetch_result<telegram_api::messages_editChatAdmin>(packet);
1223 if (result_ptr.is_error()) {
1224 return on_error(result_ptr.move_as_error());
1225 }
1226
1227 bool result = result_ptr.move_as_ok();
1228 if (!result) {
1229 LOG(ERROR) << "Receive false as result of messages.editChatAdmin";
1230 return on_error(Status::Error(400, "Can't edit chat administrators"));
1231 }
1232
1233 // result will come in the updates
1234 promise_.set_value(Unit());
1235 }
1236
on_error(Status status)1237 void on_error(Status status) final {
1238 promise_.set_error(std::move(status));
1239 td_->updates_manager_->get_difference("EditChatAdminQuery");
1240 }
1241 };
1242
1243 class ExportChatInviteQuery final : public Td::ResultHandler {
1244 Promise<td_api::object_ptr<td_api::chatInviteLink>> promise_;
1245 DialogId dialog_id_;
1246
1247 public:
ExportChatInviteQuery(Promise<td_api::object_ptr<td_api::chatInviteLink>> && promise)1248 explicit ExportChatInviteQuery(Promise<td_api::object_ptr<td_api::chatInviteLink>> &&promise)
1249 : promise_(std::move(promise)) {
1250 }
1251
send(DialogId dialog_id,const string & title,int32 expire_date,int32 usage_limit,bool creates_join_request,bool is_permanent)1252 void send(DialogId dialog_id, const string &title, int32 expire_date, int32 usage_limit, bool creates_join_request,
1253 bool is_permanent) {
1254 dialog_id_ = dialog_id;
1255 auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Write);
1256 if (input_peer == nullptr) {
1257 return on_error(Status::Error(400, "Can't access the chat"));
1258 }
1259
1260 int32 flags = 0;
1261 if (expire_date > 0) {
1262 flags |= telegram_api::messages_exportChatInvite::EXPIRE_DATE_MASK;
1263 }
1264 if (usage_limit > 0) {
1265 flags |= telegram_api::messages_exportChatInvite::USAGE_LIMIT_MASK;
1266 }
1267 if (creates_join_request) {
1268 flags |= telegram_api::messages_exportChatInvite::REQUEST_NEEDED_MASK;
1269 }
1270 if (is_permanent) {
1271 flags |= telegram_api::messages_exportChatInvite::LEGACY_REVOKE_PERMANENT_MASK;
1272 }
1273 if (!title.empty()) {
1274 flags |= telegram_api::messages_exportChatInvite::TITLE_MASK;
1275 }
1276
1277 send_query(G()->net_query_creator().create(telegram_api::messages_exportChatInvite(
1278 flags, false /*ignored*/, false /*ignored*/, std::move(input_peer), expire_date, usage_limit, title)));
1279 }
1280
on_result(BufferSlice packet)1281 void on_result(BufferSlice packet) final {
1282 auto result_ptr = fetch_result<telegram_api::messages_exportChatInvite>(packet);
1283 if (result_ptr.is_error()) {
1284 return on_error(result_ptr.move_as_error());
1285 }
1286
1287 auto ptr = result_ptr.move_as_ok();
1288 LOG(INFO) << "Receive result for ExportChatInviteQuery: " << to_string(ptr);
1289
1290 DialogInviteLink invite_link(std::move(ptr));
1291 if (!invite_link.is_valid()) {
1292 return on_error(Status::Error(500, "Receive invalid invite link"));
1293 }
1294 if (invite_link.get_creator_user_id() != td_->contacts_manager_->get_my_id()) {
1295 return on_error(Status::Error(500, "Receive invalid invite link creator"));
1296 }
1297 if (invite_link.is_permanent()) {
1298 td_->contacts_manager_->on_get_permanent_dialog_invite_link(dialog_id_, invite_link);
1299 }
1300 promise_.set_value(invite_link.get_chat_invite_link_object(td_->contacts_manager_.get()));
1301 }
1302
on_error(Status status)1303 void on_error(Status status) final {
1304 td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "ExportChatInviteQuery");
1305 promise_.set_error(std::move(status));
1306 }
1307 };
1308
1309 class EditChatInviteLinkQuery final : public Td::ResultHandler {
1310 Promise<td_api::object_ptr<td_api::chatInviteLink>> promise_;
1311 DialogId dialog_id_;
1312
1313 public:
EditChatInviteLinkQuery(Promise<td_api::object_ptr<td_api::chatInviteLink>> && promise)1314 explicit EditChatInviteLinkQuery(Promise<td_api::object_ptr<td_api::chatInviteLink>> &&promise)
1315 : promise_(std::move(promise)) {
1316 }
1317
send(DialogId dialog_id,const string & invite_link,const string & title,int32 expire_date,int32 usage_limit,bool creates_join_request)1318 void send(DialogId dialog_id, const string &invite_link, const string &title, int32 expire_date, int32 usage_limit,
1319 bool creates_join_request) {
1320 dialog_id_ = dialog_id;
1321 auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Write);
1322 if (input_peer == nullptr) {
1323 return on_error(Status::Error(400, "Can't access the chat"));
1324 }
1325
1326 int32 flags = telegram_api::messages_editExportedChatInvite::EXPIRE_DATE_MASK |
1327 telegram_api::messages_editExportedChatInvite::USAGE_LIMIT_MASK |
1328 telegram_api::messages_editExportedChatInvite::REQUEST_NEEDED_MASK |
1329 telegram_api::messages_editExportedChatInvite::TITLE_MASK;
1330 send_query(G()->net_query_creator().create(
1331 telegram_api::messages_editExportedChatInvite(flags, false /*ignored*/, std::move(input_peer), invite_link,
1332 expire_date, usage_limit, creates_join_request, title)));
1333 }
1334
on_result(BufferSlice packet)1335 void on_result(BufferSlice packet) final {
1336 auto result_ptr = fetch_result<telegram_api::messages_editExportedChatInvite>(packet);
1337 if (result_ptr.is_error()) {
1338 return on_error(result_ptr.move_as_error());
1339 }
1340
1341 auto result = result_ptr.move_as_ok();
1342 LOG(INFO) << "Receive result for EditChatInviteLinkQuery: " << to_string(result);
1343
1344 if (result->get_id() != telegram_api::messages_exportedChatInvite::ID) {
1345 return on_error(Status::Error(500, "Receive unexpected response from server"));
1346 }
1347
1348 auto invite = move_tl_object_as<telegram_api::messages_exportedChatInvite>(result);
1349
1350 td_->contacts_manager_->on_get_users(std::move(invite->users_), "EditChatInviteLinkQuery");
1351
1352 DialogInviteLink invite_link(std::move(invite->invite_));
1353 if (!invite_link.is_valid()) {
1354 return on_error(Status::Error(500, "Receive invalid invite link"));
1355 }
1356 promise_.set_value(invite_link.get_chat_invite_link_object(td_->contacts_manager_.get()));
1357 }
1358
on_error(Status status)1359 void on_error(Status status) final {
1360 td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "EditChatInviteLinkQuery");
1361 promise_.set_error(std::move(status));
1362 }
1363 };
1364
1365 class GetExportedChatInviteQuery final : public Td::ResultHandler {
1366 Promise<td_api::object_ptr<td_api::chatInviteLink>> promise_;
1367 DialogId dialog_id_;
1368
1369 public:
GetExportedChatInviteQuery(Promise<td_api::object_ptr<td_api::chatInviteLink>> && promise)1370 explicit GetExportedChatInviteQuery(Promise<td_api::object_ptr<td_api::chatInviteLink>> &&promise)
1371 : promise_(std::move(promise)) {
1372 }
1373
send(DialogId dialog_id,const string & invite_link)1374 void send(DialogId dialog_id, const string &invite_link) {
1375 dialog_id_ = dialog_id;
1376 auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Write);
1377 if (input_peer == nullptr) {
1378 return on_error(Status::Error(400, "Can't access the chat"));
1379 }
1380
1381 send_query(G()->net_query_creator().create(
1382 telegram_api::messages_getExportedChatInvite(std::move(input_peer), invite_link)));
1383 }
1384
on_result(BufferSlice packet)1385 void on_result(BufferSlice packet) final {
1386 auto result_ptr = fetch_result<telegram_api::messages_getExportedChatInvite>(packet);
1387 if (result_ptr.is_error()) {
1388 return on_error(result_ptr.move_as_error());
1389 }
1390
1391 if (result_ptr.ok()->get_id() != telegram_api::messages_exportedChatInvite::ID) {
1392 LOG(ERROR) << "Receive wrong result for GetExportedChatInviteQuery: " << to_string(result_ptr.ok());
1393 return on_error(Status::Error(500, "Receive unexpected response"));
1394 }
1395
1396 auto result = move_tl_object_as<telegram_api::messages_exportedChatInvite>(result_ptr.ok_ref());
1397 LOG(INFO) << "Receive result for GetExportedChatInviteQuery: " << to_string(result);
1398
1399 td_->contacts_manager_->on_get_users(std::move(result->users_), "GetExportedChatInviteQuery");
1400
1401 DialogInviteLink invite_link(std::move(result->invite_));
1402 if (!invite_link.is_valid()) {
1403 LOG(ERROR) << "Receive invalid invite link in " << dialog_id_;
1404 return on_error(Status::Error(500, "Receive invalid invite link"));
1405 }
1406 promise_.set_value(invite_link.get_chat_invite_link_object(td_->contacts_manager_.get()));
1407 }
1408
on_error(Status status)1409 void on_error(Status status) final {
1410 td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "GetExportedChatInviteQuery");
1411 promise_.set_error(std::move(status));
1412 }
1413 };
1414
1415 class GetExportedChatInvitesQuery final : public Td::ResultHandler {
1416 Promise<td_api::object_ptr<td_api::chatInviteLinks>> promise_;
1417 DialogId dialog_id_;
1418
1419 public:
GetExportedChatInvitesQuery(Promise<td_api::object_ptr<td_api::chatInviteLinks>> && promise)1420 explicit GetExportedChatInvitesQuery(Promise<td_api::object_ptr<td_api::chatInviteLinks>> &&promise)
1421 : promise_(std::move(promise)) {
1422 }
1423
send(DialogId dialog_id,UserId creator_user_id,bool is_revoked,int32 offset_date,const string & offset_invite_link,int32 limit)1424 void send(DialogId dialog_id, UserId creator_user_id, bool is_revoked, int32 offset_date,
1425 const string &offset_invite_link, int32 limit) {
1426 dialog_id_ = dialog_id;
1427 auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Write);
1428 if (input_peer == nullptr) {
1429 return on_error(Status::Error(400, "Can't access the chat"));
1430 }
1431
1432 auto input_user = td_->contacts_manager_->get_input_user(creator_user_id);
1433 CHECK(input_user != nullptr);
1434
1435 int32 flags = 0;
1436 if (!offset_invite_link.empty() || offset_date != 0) {
1437 flags |= telegram_api::messages_getExportedChatInvites::OFFSET_DATE_MASK;
1438 flags |= telegram_api::messages_getExportedChatInvites::OFFSET_LINK_MASK;
1439 }
1440 if (is_revoked) {
1441 flags |= telegram_api::messages_getExportedChatInvites::REVOKED_MASK;
1442 }
1443 send_query(G()->net_query_creator().create(
1444 telegram_api::messages_getExportedChatInvites(flags, false /*ignored*/, std::move(input_peer),
1445 std::move(input_user), offset_date, offset_invite_link, limit)));
1446 }
1447
on_result(BufferSlice packet)1448 void on_result(BufferSlice packet) final {
1449 auto result_ptr = fetch_result<telegram_api::messages_getExportedChatInvites>(packet);
1450 if (result_ptr.is_error()) {
1451 return on_error(result_ptr.move_as_error());
1452 }
1453
1454 auto result = result_ptr.move_as_ok();
1455 LOG(INFO) << "Receive result for GetExportedChatInvitesQuery: " << to_string(result);
1456
1457 td_->contacts_manager_->on_get_users(std::move(result->users_), "GetExportedChatInvitesQuery");
1458
1459 int32 total_count = result->count_;
1460 if (total_count < static_cast<int32>(result->invites_.size())) {
1461 LOG(ERROR) << "Receive wrong total count of invite links " << total_count << " in " << dialog_id_;
1462 total_count = static_cast<int32>(result->invites_.size());
1463 }
1464 vector<td_api::object_ptr<td_api::chatInviteLink>> invite_links;
1465 for (auto &invite : result->invites_) {
1466 DialogInviteLink invite_link(std::move(invite));
1467 if (!invite_link.is_valid()) {
1468 LOG(ERROR) << "Receive invalid invite link in " << dialog_id_;
1469 total_count--;
1470 continue;
1471 }
1472 invite_links.push_back(invite_link.get_chat_invite_link_object(td_->contacts_manager_.get()));
1473 }
1474 promise_.set_value(td_api::make_object<td_api::chatInviteLinks>(total_count, std::move(invite_links)));
1475 }
1476
on_error(Status status)1477 void on_error(Status status) final {
1478 td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "GetExportedChatInvitesQuery");
1479 promise_.set_error(std::move(status));
1480 }
1481 };
1482
1483 class GetChatAdminWithInvitesQuery final : public Td::ResultHandler {
1484 Promise<td_api::object_ptr<td_api::chatInviteLinkCounts>> promise_;
1485 DialogId dialog_id_;
1486
1487 public:
GetChatAdminWithInvitesQuery(Promise<td_api::object_ptr<td_api::chatInviteLinkCounts>> && promise)1488 explicit GetChatAdminWithInvitesQuery(Promise<td_api::object_ptr<td_api::chatInviteLinkCounts>> &&promise)
1489 : promise_(std::move(promise)) {
1490 }
1491
send(DialogId dialog_id)1492 void send(DialogId dialog_id) {
1493 dialog_id_ = dialog_id;
1494 auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Write);
1495 if (input_peer == nullptr) {
1496 return on_error(Status::Error(400, "Can't access the chat"));
1497 }
1498
1499 send_query(G()->net_query_creator().create(telegram_api::messages_getAdminsWithInvites(std::move(input_peer))));
1500 }
1501
on_result(BufferSlice packet)1502 void on_result(BufferSlice packet) final {
1503 auto result_ptr = fetch_result<telegram_api::messages_getAdminsWithInvites>(packet);
1504 if (result_ptr.is_error()) {
1505 return on_error(result_ptr.move_as_error());
1506 }
1507
1508 auto result = result_ptr.move_as_ok();
1509 LOG(INFO) << "Receive result for GetChatAdminWithInvitesQuery: " << to_string(result);
1510
1511 td_->contacts_manager_->on_get_users(std::move(result->users_), "GetChatAdminWithInvitesQuery");
1512
1513 vector<td_api::object_ptr<td_api::chatInviteLinkCount>> invite_link_counts;
1514 for (auto &admin : result->admins_) {
1515 UserId user_id(admin->admin_id_);
1516 if (!user_id.is_valid()) {
1517 LOG(ERROR) << "Receive invalid invite link creator " << user_id << " in " << dialog_id_;
1518 continue;
1519 }
1520 invite_link_counts.push_back(td_api::make_object<td_api::chatInviteLinkCount>(
1521 td_->contacts_manager_->get_user_id_object(user_id, "chatInviteLinkCount"), admin->invites_count_,
1522 admin->revoked_invites_count_));
1523 }
1524 promise_.set_value(td_api::make_object<td_api::chatInviteLinkCounts>(std::move(invite_link_counts)));
1525 }
1526
on_error(Status status)1527 void on_error(Status status) final {
1528 td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "GetChatAdminWithInvitesQuery");
1529 promise_.set_error(std::move(status));
1530 }
1531 };
1532
1533 class GetChatInviteImportersQuery final : public Td::ResultHandler {
1534 Promise<td_api::object_ptr<td_api::chatInviteLinkMembers>> promise_;
1535 DialogId dialog_id_;
1536
1537 public:
GetChatInviteImportersQuery(Promise<td_api::object_ptr<td_api::chatInviteLinkMembers>> && promise)1538 explicit GetChatInviteImportersQuery(Promise<td_api::object_ptr<td_api::chatInviteLinkMembers>> &&promise)
1539 : promise_(std::move(promise)) {
1540 }
1541
send(DialogId dialog_id,const string & invite_link,int32 offset_date,UserId offset_user_id,int32 limit)1542 void send(DialogId dialog_id, const string &invite_link, int32 offset_date, UserId offset_user_id, int32 limit) {
1543 dialog_id_ = dialog_id;
1544 auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Write);
1545 if (input_peer == nullptr) {
1546 return on_error(Status::Error(400, "Can't access the chat"));
1547 }
1548
1549 auto input_user = td_->contacts_manager_->get_input_user(offset_user_id);
1550 if (input_user == nullptr) {
1551 input_user = make_tl_object<telegram_api::inputUserEmpty>();
1552 }
1553
1554 int32 flags = telegram_api::messages_getChatInviteImporters::LINK_MASK;
1555 send_query(G()->net_query_creator().create(
1556 telegram_api::messages_getChatInviteImporters(flags, false /*ignored*/, std::move(input_peer), invite_link,
1557 string(), offset_date, std::move(input_user), limit)));
1558 }
1559
on_result(BufferSlice packet)1560 void on_result(BufferSlice packet) final {
1561 auto result_ptr = fetch_result<telegram_api::messages_getChatInviteImporters>(packet);
1562 if (result_ptr.is_error()) {
1563 return on_error(result_ptr.move_as_error());
1564 }
1565
1566 auto result = result_ptr.move_as_ok();
1567 LOG(INFO) << "Receive result for GetChatInviteImportersQuery: " << to_string(result);
1568
1569 td_->contacts_manager_->on_get_users(std::move(result->users_), "GetChatInviteImportersQuery");
1570
1571 int32 total_count = result->count_;
1572 if (total_count < static_cast<int32>(result->importers_.size())) {
1573 LOG(ERROR) << "Receive wrong total count of invite link users " << total_count << " in " << dialog_id_;
1574 total_count = static_cast<int32>(result->importers_.size());
1575 }
1576 vector<td_api::object_ptr<td_api::chatInviteLinkMember>> invite_link_members;
1577 for (auto &importer : result->importers_) {
1578 UserId user_id(importer->user_id_);
1579 UserId approver_user_id(importer->approved_by_);
1580 if (!user_id.is_valid() || (!approver_user_id.is_valid() && approver_user_id != UserId()) ||
1581 importer->requested_) {
1582 LOG(ERROR) << "Receive invalid invite link importer: " << to_string(importer);
1583 total_count--;
1584 continue;
1585 }
1586 invite_link_members.push_back(td_api::make_object<td_api::chatInviteLinkMember>(
1587 td_->contacts_manager_->get_user_id_object(user_id, "chatInviteLinkMember"), importer->date_,
1588 td_->contacts_manager_->get_user_id_object(approver_user_id, "chatInviteLinkMember")));
1589 }
1590 promise_.set_value(td_api::make_object<td_api::chatInviteLinkMembers>(total_count, std::move(invite_link_members)));
1591 }
1592
on_error(Status status)1593 void on_error(Status status) final {
1594 td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "GetChatInviteImportersQuery");
1595 promise_.set_error(std::move(status));
1596 }
1597 };
1598
1599 class GetChatJoinRequestsQuery final : public Td::ResultHandler {
1600 Promise<td_api::object_ptr<td_api::chatJoinRequests>> promise_;
1601 DialogId dialog_id_;
1602 bool is_full_list_ = false;
1603
1604 public:
GetChatJoinRequestsQuery(Promise<td_api::object_ptr<td_api::chatJoinRequests>> && promise)1605 explicit GetChatJoinRequestsQuery(Promise<td_api::object_ptr<td_api::chatJoinRequests>> &&promise)
1606 : promise_(std::move(promise)) {
1607 }
1608
send(DialogId dialog_id,const string & invite_link,const string & query,int32 offset_date,UserId offset_user_id,int32 limit)1609 void send(DialogId dialog_id, const string &invite_link, const string &query, int32 offset_date,
1610 UserId offset_user_id, int32 limit) {
1611 dialog_id_ = dialog_id;
1612 is_full_list_ =
1613 invite_link.empty() && query.empty() && offset_date == 0 && !offset_user_id.is_valid() && limit >= 3;
1614
1615 auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Write);
1616 if (input_peer == nullptr) {
1617 return on_error(Status::Error(400, "Can't access the chat"));
1618 }
1619
1620 auto input_user = td_->contacts_manager_->get_input_user(offset_user_id);
1621 if (input_user == nullptr) {
1622 input_user = make_tl_object<telegram_api::inputUserEmpty>();
1623 }
1624
1625 int32 flags = telegram_api::messages_getChatInviteImporters::REQUESTED_MASK;
1626 if (!invite_link.empty()) {
1627 flags |= telegram_api::messages_getChatInviteImporters::LINK_MASK;
1628 }
1629 if (!query.empty()) {
1630 flags |= telegram_api::messages_getChatInviteImporters::Q_MASK;
1631 }
1632 send_query(G()->net_query_creator().create(
1633 telegram_api::messages_getChatInviteImporters(flags, false /*ignored*/, std::move(input_peer), invite_link,
1634 query, offset_date, std::move(input_user), limit)));
1635 }
1636
on_result(BufferSlice packet)1637 void on_result(BufferSlice packet) final {
1638 auto result_ptr = fetch_result<telegram_api::messages_getChatInviteImporters>(packet);
1639 if (result_ptr.is_error()) {
1640 return on_error(result_ptr.move_as_error());
1641 }
1642
1643 auto result = result_ptr.move_as_ok();
1644 LOG(INFO) << "Receive result for GetChatJoinRequestsQuery: " << to_string(result);
1645
1646 td_->contacts_manager_->on_get_users(std::move(result->users_), "GetChatJoinRequestsQuery");
1647
1648 int32 total_count = result->count_;
1649 if (total_count < static_cast<int32>(result->importers_.size())) {
1650 LOG(ERROR) << "Receive wrong total count of join requests " << total_count << " in " << dialog_id_;
1651 total_count = static_cast<int32>(result->importers_.size());
1652 }
1653 vector<td_api::object_ptr<td_api::chatJoinRequest>> join_requests;
1654 vector<int64> recent_requesters;
1655 for (auto &request : result->importers_) {
1656 UserId user_id(request->user_id_);
1657 UserId approver_user_id(request->approved_by_);
1658 if (!user_id.is_valid() || approver_user_id.is_valid() || !request->requested_) {
1659 LOG(ERROR) << "Receive invalid join request: " << to_string(request);
1660 total_count--;
1661 continue;
1662 }
1663 if (recent_requesters.size() < 3) {
1664 recent_requesters.push_back(user_id.get());
1665 }
1666 join_requests.push_back(td_api::make_object<td_api::chatJoinRequest>(
1667 td_->contacts_manager_->get_user_id_object(user_id, "chatJoinRequest"), request->date_, request->about_));
1668 }
1669 if (is_full_list_) {
1670 td_->messages_manager_->on_update_dialog_pending_join_requests(dialog_id_, total_count,
1671 std::move(recent_requesters));
1672 }
1673 promise_.set_value(td_api::make_object<td_api::chatJoinRequests>(total_count, std::move(join_requests)));
1674 }
1675
on_error(Status status)1676 void on_error(Status status) final {
1677 td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "GetChatJoinRequestsQuery");
1678 promise_.set_error(std::move(status));
1679 }
1680 };
1681
1682 class HideChatJoinRequestQuery final : public Td::ResultHandler {
1683 Promise<Unit> promise_;
1684 DialogId dialog_id_;
1685
1686 public:
HideChatJoinRequestQuery(Promise<Unit> && promise)1687 explicit HideChatJoinRequestQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
1688 }
1689
send(DialogId dialog_id,UserId user_id,bool approve)1690 void send(DialogId dialog_id, UserId user_id, bool approve) {
1691 dialog_id_ = dialog_id;
1692 auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Write);
1693 if (input_peer == nullptr) {
1694 return on_error(Status::Error(400, "Can't access the chat"));
1695 }
1696
1697 auto input_user = td_->contacts_manager_->get_input_user(user_id);
1698 if (input_user == nullptr) {
1699 return on_error(Status::Error(400, "Can't find user"));
1700 }
1701
1702 int32 flags = 0;
1703 if (approve) {
1704 flags |= telegram_api::messages_hideChatJoinRequest::APPROVED_MASK;
1705 }
1706 send_query(G()->net_query_creator().create(telegram_api::messages_hideChatJoinRequest(
1707 flags, false /*ignored*/, std::move(input_peer), std::move(input_user))));
1708 }
1709
on_result(BufferSlice packet)1710 void on_result(BufferSlice packet) final {
1711 auto result_ptr = fetch_result<telegram_api::messages_hideChatJoinRequest>(packet);
1712 if (result_ptr.is_error()) {
1713 return on_error(result_ptr.move_as_error());
1714 }
1715
1716 auto result = result_ptr.move_as_ok();
1717 LOG(INFO) << "Receive result for HideChatJoinRequestQuery: " << to_string(result);
1718 td_->updates_manager_->on_get_updates(std::move(result), std::move(promise_));
1719 }
1720
on_error(Status status)1721 void on_error(Status status) final {
1722 td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "HideChatJoinRequestQuery");
1723 promise_.set_error(std::move(status));
1724 }
1725 };
1726
1727 class HideAllChatJoinRequestsQuery final : public Td::ResultHandler {
1728 Promise<Unit> promise_;
1729 DialogId dialog_id_;
1730
1731 public:
HideAllChatJoinRequestsQuery(Promise<Unit> && promise)1732 explicit HideAllChatJoinRequestsQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
1733 }
1734
send(DialogId dialog_id,const string & invite_link,bool approve)1735 void send(DialogId dialog_id, const string &invite_link, bool approve) {
1736 dialog_id_ = dialog_id;
1737 auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Write);
1738 if (input_peer == nullptr) {
1739 return on_error(Status::Error(400, "Can't access the chat"));
1740 }
1741
1742 int32 flags = 0;
1743 if (approve) {
1744 flags |= telegram_api::messages_hideAllChatJoinRequests::APPROVED_MASK;
1745 }
1746 if (!invite_link.empty()) {
1747 flags |= telegram_api::messages_hideAllChatJoinRequests::LINK_MASK;
1748 }
1749 send_query(G()->net_query_creator().create(
1750 telegram_api::messages_hideAllChatJoinRequests(flags, false /*ignored*/, std::move(input_peer), invite_link)));
1751 }
1752
on_result(BufferSlice packet)1753 void on_result(BufferSlice packet) final {
1754 auto result_ptr = fetch_result<telegram_api::messages_hideAllChatJoinRequests>(packet);
1755 if (result_ptr.is_error()) {
1756 return on_error(result_ptr.move_as_error());
1757 }
1758
1759 auto result = result_ptr.move_as_ok();
1760 LOG(INFO) << "Receive result for HideAllChatJoinRequestsQuery: " << to_string(result);
1761 td_->updates_manager_->on_get_updates(std::move(result), std::move(promise_));
1762 }
1763
on_error(Status status)1764 void on_error(Status status) final {
1765 td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "HideAllChatJoinRequestsQuery");
1766 promise_.set_error(std::move(status));
1767 }
1768 };
1769
1770 class RevokeChatInviteLinkQuery final : public Td::ResultHandler {
1771 Promise<td_api::object_ptr<td_api::chatInviteLinks>> promise_;
1772 DialogId dialog_id_;
1773
1774 public:
RevokeChatInviteLinkQuery(Promise<td_api::object_ptr<td_api::chatInviteLinks>> && promise)1775 explicit RevokeChatInviteLinkQuery(Promise<td_api::object_ptr<td_api::chatInviteLinks>> &&promise)
1776 : promise_(std::move(promise)) {
1777 }
1778
send(DialogId dialog_id,const string & invite_link)1779 void send(DialogId dialog_id, const string &invite_link) {
1780 dialog_id_ = dialog_id;
1781 auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Write);
1782 if (input_peer == nullptr) {
1783 return on_error(Status::Error(400, "Can't access the chat"));
1784 }
1785
1786 int32 flags = telegram_api::messages_editExportedChatInvite::REVOKED_MASK;
1787 send_query(G()->net_query_creator().create(telegram_api::messages_editExportedChatInvite(
1788 flags, false /*ignored*/, std::move(input_peer), invite_link, 0, 0, false, string())));
1789 }
1790
on_result(BufferSlice packet)1791 void on_result(BufferSlice packet) final {
1792 auto result_ptr = fetch_result<telegram_api::messages_editExportedChatInvite>(packet);
1793 if (result_ptr.is_error()) {
1794 return on_error(result_ptr.move_as_error());
1795 }
1796
1797 auto result = result_ptr.move_as_ok();
1798 LOG(INFO) << "Receive result for RevokeChatInviteLinkQuery: " << to_string(result);
1799
1800 vector<td_api::object_ptr<td_api::chatInviteLink>> links;
1801 switch (result->get_id()) {
1802 case telegram_api::messages_exportedChatInvite::ID: {
1803 auto invite = move_tl_object_as<telegram_api::messages_exportedChatInvite>(result);
1804
1805 td_->contacts_manager_->on_get_users(std::move(invite->users_), "RevokeChatInviteLinkQuery");
1806
1807 DialogInviteLink invite_link(std::move(invite->invite_));
1808 if (!invite_link.is_valid()) {
1809 return on_error(Status::Error(500, "Receive invalid invite link"));
1810 }
1811 links.push_back(invite_link.get_chat_invite_link_object(td_->contacts_manager_.get()));
1812 break;
1813 }
1814 case telegram_api::messages_exportedChatInviteReplaced::ID: {
1815 auto invite = move_tl_object_as<telegram_api::messages_exportedChatInviteReplaced>(result);
1816
1817 td_->contacts_manager_->on_get_users(std::move(invite->users_), "RevokeChatInviteLinkQuery");
1818
1819 DialogInviteLink invite_link(std::move(invite->invite_));
1820 DialogInviteLink new_invite_link(std::move(invite->new_invite_));
1821 if (!invite_link.is_valid() || !new_invite_link.is_valid()) {
1822 return on_error(Status::Error(500, "Receive invalid invite link"));
1823 }
1824 if (new_invite_link.get_creator_user_id() == td_->contacts_manager_->get_my_id() &&
1825 new_invite_link.is_permanent()) {
1826 td_->contacts_manager_->on_get_permanent_dialog_invite_link(dialog_id_, new_invite_link);
1827 }
1828 links.push_back(invite_link.get_chat_invite_link_object(td_->contacts_manager_.get()));
1829 links.push_back(new_invite_link.get_chat_invite_link_object(td_->contacts_manager_.get()));
1830 break;
1831 }
1832 default:
1833 UNREACHABLE();
1834 }
1835 auto total_count = static_cast<int32>(links.size());
1836 promise_.set_value(td_api::make_object<td_api::chatInviteLinks>(total_count, std::move(links)));
1837 }
1838
on_error(Status status)1839 void on_error(Status status) final {
1840 td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "RevokeChatInviteLinkQuery");
1841 promise_.set_error(std::move(status));
1842 }
1843 };
1844
1845 class DeleteExportedChatInviteQuery final : public Td::ResultHandler {
1846 Promise<Unit> promise_;
1847 DialogId dialog_id_;
1848
1849 public:
DeleteExportedChatInviteQuery(Promise<Unit> && promise)1850 explicit DeleteExportedChatInviteQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
1851 }
1852
send(DialogId dialog_id,const string & invite_link)1853 void send(DialogId dialog_id, const string &invite_link) {
1854 dialog_id_ = dialog_id;
1855 auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Write);
1856 if (input_peer == nullptr) {
1857 return on_error(Status::Error(400, "Can't access the chat"));
1858 }
1859
1860 send_query(G()->net_query_creator().create(
1861 telegram_api::messages_deleteExportedChatInvite(std::move(input_peer), invite_link)));
1862 }
1863
on_result(BufferSlice packet)1864 void on_result(BufferSlice packet) final {
1865 auto result_ptr = fetch_result<telegram_api::messages_deleteExportedChatInvite>(packet);
1866 if (result_ptr.is_error()) {
1867 return on_error(result_ptr.move_as_error());
1868 }
1869
1870 promise_.set_value(Unit());
1871 }
1872
on_error(Status status)1873 void on_error(Status status) final {
1874 td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "DeleteExportedChatInviteQuery");
1875 promise_.set_error(std::move(status));
1876 }
1877 };
1878
1879 class DeleteRevokedExportedChatInvitesQuery final : public Td::ResultHandler {
1880 Promise<Unit> promise_;
1881 DialogId dialog_id_;
1882
1883 public:
DeleteRevokedExportedChatInvitesQuery(Promise<Unit> && promise)1884 explicit DeleteRevokedExportedChatInvitesQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
1885 }
1886
send(DialogId dialog_id,UserId creator_user_id)1887 void send(DialogId dialog_id, UserId creator_user_id) {
1888 dialog_id_ = dialog_id;
1889 auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Write);
1890 if (input_peer == nullptr) {
1891 return on_error(Status::Error(400, "Can't access the chat"));
1892 }
1893
1894 auto input_user = td_->contacts_manager_->get_input_user(creator_user_id);
1895 CHECK(input_user != nullptr);
1896
1897 send_query(G()->net_query_creator().create(
1898 telegram_api::messages_deleteRevokedExportedChatInvites(std::move(input_peer), std::move(input_user))));
1899 }
1900
on_result(BufferSlice packet)1901 void on_result(BufferSlice packet) final {
1902 auto result_ptr = fetch_result<telegram_api::messages_deleteRevokedExportedChatInvites>(packet);
1903 if (result_ptr.is_error()) {
1904 return on_error(result_ptr.move_as_error());
1905 }
1906
1907 promise_.set_value(Unit());
1908 }
1909
on_error(Status status)1910 void on_error(Status status) final {
1911 td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "DeleteRevokedExportedChatInvitesQuery");
1912 promise_.set_error(std::move(status));
1913 }
1914 };
1915
1916 class CheckChatInviteQuery final : public Td::ResultHandler {
1917 Promise<Unit> promise_;
1918 string invite_link_;
1919
1920 public:
CheckChatInviteQuery(Promise<Unit> && promise)1921 explicit CheckChatInviteQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
1922 }
1923
send(const string & invite_link)1924 void send(const string &invite_link) {
1925 invite_link_ = invite_link;
1926 send_query(G()->net_query_creator().create(
1927 telegram_api::messages_checkChatInvite(LinkManager::get_dialog_invite_link_hash(invite_link_))));
1928 }
1929
on_result(BufferSlice packet)1930 void on_result(BufferSlice packet) final {
1931 auto result_ptr = fetch_result<telegram_api::messages_checkChatInvite>(packet);
1932 if (result_ptr.is_error()) {
1933 return on_error(result_ptr.move_as_error());
1934 }
1935
1936 auto ptr = result_ptr.move_as_ok();
1937 LOG(INFO) << "Receive result for CheckChatInviteQuery: " << to_string(ptr);
1938
1939 td_->contacts_manager_->on_get_dialog_invite_link_info(invite_link_, std::move(ptr), std::move(promise_));
1940 }
1941
on_error(Status status)1942 void on_error(Status status) final {
1943 promise_.set_error(std::move(status));
1944 }
1945 };
1946
1947 class ImportChatInviteQuery final : public Td::ResultHandler {
1948 Promise<DialogId> promise_;
1949
1950 string invite_link_;
1951
1952 public:
ImportChatInviteQuery(Promise<DialogId> && promise)1953 explicit ImportChatInviteQuery(Promise<DialogId> &&promise) : promise_(std::move(promise)) {
1954 }
1955
send(const string & invite_link)1956 void send(const string &invite_link) {
1957 invite_link_ = invite_link;
1958 send_query(G()->net_query_creator().create(
1959 telegram_api::messages_importChatInvite(LinkManager::get_dialog_invite_link_hash(invite_link_))));
1960 }
1961
on_result(BufferSlice packet)1962 void on_result(BufferSlice packet) final {
1963 auto result_ptr = fetch_result<telegram_api::messages_importChatInvite>(packet);
1964 if (result_ptr.is_error()) {
1965 return on_error(result_ptr.move_as_error());
1966 }
1967
1968 auto ptr = result_ptr.move_as_ok();
1969 LOG(INFO) << "Receive result for ImportChatInviteQuery: " << to_string(ptr);
1970
1971 auto dialog_ids = UpdatesManager::get_chat_dialog_ids(ptr.get());
1972 if (dialog_ids.size() != 1u) {
1973 LOG(ERROR) << "Receive wrong result for ImportChatInviteQuery: " << to_string(ptr);
1974 return on_error(Status::Error(500, "Internal Server Error: failed to join chat by invite link"));
1975 }
1976 auto dialog_id = dialog_ids[0];
1977
1978 td_->contacts_manager_->invalidate_invite_link_info(invite_link_);
1979 td_->updates_manager_->on_get_updates(
1980 std::move(ptr), PromiseCreator::lambda([promise = std::move(promise_), dialog_id](Unit) mutable {
1981 promise.set_value(std::move(dialog_id));
1982 }));
1983 }
1984
on_error(Status status)1985 void on_error(Status status) final {
1986 td_->contacts_manager_->invalidate_invite_link_info(invite_link_);
1987 promise_.set_error(std::move(status));
1988 }
1989 };
1990
1991 class DeleteChatUserQuery final : public Td::ResultHandler {
1992 Promise<Unit> promise_;
1993
1994 public:
DeleteChatUserQuery(Promise<Unit> && promise)1995 explicit DeleteChatUserQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
1996 }
1997
send(ChatId chat_id,tl_object_ptr<telegram_api::InputUser> && input_user,bool revoke_messages)1998 void send(ChatId chat_id, tl_object_ptr<telegram_api::InputUser> &&input_user, bool revoke_messages) {
1999 int32 flags = 0;
2000 if (revoke_messages) {
2001 flags |= telegram_api::messages_deleteChatUser::REVOKE_HISTORY_MASK;
2002 }
2003 send_query(G()->net_query_creator().create(
2004 telegram_api::messages_deleteChatUser(flags, false /*ignored*/, chat_id.get(), std::move(input_user))));
2005 }
2006
on_result(BufferSlice packet)2007 void on_result(BufferSlice packet) final {
2008 auto result_ptr = fetch_result<telegram_api::messages_deleteChatUser>(packet);
2009 if (result_ptr.is_error()) {
2010 return on_error(result_ptr.move_as_error());
2011 }
2012
2013 auto ptr = result_ptr.move_as_ok();
2014 LOG(INFO) << "Receive result for DeleteChatUserQuery: " << to_string(ptr);
2015 td_->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_));
2016 }
2017
on_error(Status status)2018 void on_error(Status status) final {
2019 promise_.set_error(std::move(status));
2020 td_->updates_manager_->get_difference("DeleteChatUserQuery");
2021 }
2022 };
2023
2024 class JoinChannelQuery final : public Td::ResultHandler {
2025 Promise<Unit> promise_;
2026 ChannelId channel_id_;
2027
2028 public:
JoinChannelQuery(Promise<Unit> && promise)2029 explicit JoinChannelQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
2030 }
2031
send(ChannelId channel_id)2032 void send(ChannelId channel_id) {
2033 channel_id_ = channel_id;
2034 auto input_channel = td_->contacts_manager_->get_input_channel(channel_id);
2035 CHECK(input_channel != nullptr);
2036 send_query(G()->net_query_creator().create(telegram_api::channels_joinChannel(std::move(input_channel))));
2037 }
2038
on_result(BufferSlice packet)2039 void on_result(BufferSlice packet) final {
2040 auto result_ptr = fetch_result<telegram_api::channels_joinChannel>(packet);
2041 if (result_ptr.is_error()) {
2042 return on_error(result_ptr.move_as_error());
2043 }
2044
2045 auto ptr = result_ptr.move_as_ok();
2046 LOG(INFO) << "Receive result for JoinChannelQuery: " << to_string(ptr);
2047 td_->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_));
2048 }
2049
on_error(Status status)2050 void on_error(Status status) final {
2051 td_->contacts_manager_->on_get_channel_error(channel_id_, status, "JoinChannelQuery");
2052 promise_.set_error(std::move(status));
2053 td_->updates_manager_->get_difference("JoinChannelQuery");
2054 }
2055 };
2056
2057 class InviteToChannelQuery final : public Td::ResultHandler {
2058 Promise<Unit> promise_;
2059 ChannelId channel_id_;
2060
2061 public:
InviteToChannelQuery(Promise<Unit> && promise)2062 explicit InviteToChannelQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
2063 }
2064
send(ChannelId channel_id,vector<tl_object_ptr<telegram_api::InputUser>> && input_users)2065 void send(ChannelId channel_id, vector<tl_object_ptr<telegram_api::InputUser>> &&input_users) {
2066 channel_id_ = channel_id;
2067 auto input_channel = td_->contacts_manager_->get_input_channel(channel_id);
2068 CHECK(input_channel != nullptr);
2069 send_query(G()->net_query_creator().create(
2070 telegram_api::channels_inviteToChannel(std::move(input_channel), std::move(input_users))));
2071 }
2072
on_result(BufferSlice packet)2073 void on_result(BufferSlice packet) final {
2074 auto result_ptr = fetch_result<telegram_api::channels_inviteToChannel>(packet);
2075 if (result_ptr.is_error()) {
2076 return on_error(result_ptr.move_as_error());
2077 }
2078
2079 auto ptr = result_ptr.move_as_ok();
2080 LOG(INFO) << "Receive result for InviteToChannelQuery: " << to_string(ptr);
2081 td_->contacts_manager_->invalidate_channel_full(channel_id_, false);
2082 td_->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_));
2083 }
2084
on_error(Status status)2085 void on_error(Status status) final {
2086 td_->contacts_manager_->on_get_channel_error(channel_id_, status, "InviteToChannelQuery");
2087 promise_.set_error(std::move(status));
2088 td_->updates_manager_->get_difference("InviteToChannelQuery");
2089 }
2090 };
2091
2092 class EditChannelAdminQuery final : public Td::ResultHandler {
2093 Promise<Unit> promise_;
2094 ChannelId channel_id_;
2095
2096 public:
EditChannelAdminQuery(Promise<Unit> && promise)2097 explicit EditChannelAdminQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
2098 }
2099
send(ChannelId channel_id,tl_object_ptr<telegram_api::InputUser> && input_user,const DialogParticipantStatus & status)2100 void send(ChannelId channel_id, tl_object_ptr<telegram_api::InputUser> &&input_user,
2101 const DialogParticipantStatus &status) {
2102 channel_id_ = channel_id;
2103 auto input_channel = td_->contacts_manager_->get_input_channel(channel_id);
2104 CHECK(input_channel != nullptr);
2105 send_query(G()->net_query_creator().create(telegram_api::channels_editAdmin(
2106 std::move(input_channel), std::move(input_user), status.get_chat_admin_rights(), status.get_rank())));
2107 }
2108
on_result(BufferSlice packet)2109 void on_result(BufferSlice packet) final {
2110 auto result_ptr = fetch_result<telegram_api::channels_editAdmin>(packet);
2111 if (result_ptr.is_error()) {
2112 return on_error(result_ptr.move_as_error());
2113 }
2114
2115 auto ptr = result_ptr.move_as_ok();
2116 LOG(INFO) << "Receive result for EditChannelAdminQuery: " << to_string(ptr);
2117 td_->contacts_manager_->invalidate_channel_full(channel_id_, false);
2118 td_->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_));
2119 }
2120
on_error(Status status)2121 void on_error(Status status) final {
2122 td_->contacts_manager_->on_get_channel_error(channel_id_, status, "EditChannelAdminQuery");
2123 promise_.set_error(std::move(status));
2124 td_->updates_manager_->get_difference("EditChannelAdminQuery");
2125 }
2126 };
2127
2128 class EditChannelBannedQuery final : public Td::ResultHandler {
2129 Promise<Unit> promise_;
2130 ChannelId channel_id_;
2131
2132 public:
EditChannelBannedQuery(Promise<Unit> && promise)2133 explicit EditChannelBannedQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
2134 }
2135
send(ChannelId channel_id,tl_object_ptr<telegram_api::InputPeer> && input_peer,const DialogParticipantStatus & status)2136 void send(ChannelId channel_id, tl_object_ptr<telegram_api::InputPeer> &&input_peer,
2137 const DialogParticipantStatus &status) {
2138 channel_id_ = channel_id;
2139 auto input_channel = td_->contacts_manager_->get_input_channel(channel_id);
2140 CHECK(input_channel != nullptr);
2141 send_query(G()->net_query_creator().create(telegram_api::channels_editBanned(
2142 std::move(input_channel), std::move(input_peer), status.get_chat_banned_rights())));
2143 }
2144
on_result(BufferSlice packet)2145 void on_result(BufferSlice packet) final {
2146 auto result_ptr = fetch_result<telegram_api::channels_editBanned>(packet);
2147 if (result_ptr.is_error()) {
2148 return on_error(result_ptr.move_as_error());
2149 }
2150
2151 auto ptr = result_ptr.move_as_ok();
2152 LOG(INFO) << "Receive result for EditChannelBannedQuery: " << to_string(ptr);
2153 td_->contacts_manager_->invalidate_channel_full(channel_id_, false);
2154 td_->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_));
2155 }
2156
on_error(Status status)2157 void on_error(Status status) final {
2158 td_->contacts_manager_->on_get_channel_error(channel_id_, status, "EditChannelBannedQuery");
2159 promise_.set_error(std::move(status));
2160 td_->updates_manager_->get_difference("EditChannelBannedQuery");
2161 }
2162 };
2163
2164 class LeaveChannelQuery final : public Td::ResultHandler {
2165 Promise<Unit> promise_;
2166 ChannelId channel_id_;
2167
2168 public:
LeaveChannelQuery(Promise<Unit> && promise)2169 explicit LeaveChannelQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
2170 }
2171
send(ChannelId channel_id)2172 void send(ChannelId channel_id) {
2173 channel_id_ = channel_id;
2174 auto input_channel = td_->contacts_manager_->get_input_channel(channel_id);
2175 CHECK(input_channel != nullptr);
2176 send_query(G()->net_query_creator().create(telegram_api::channels_leaveChannel(std::move(input_channel))));
2177 }
2178
on_result(BufferSlice packet)2179 void on_result(BufferSlice packet) final {
2180 auto result_ptr = fetch_result<telegram_api::channels_leaveChannel>(packet);
2181 if (result_ptr.is_error()) {
2182 return on_error(result_ptr.move_as_error());
2183 }
2184
2185 auto ptr = result_ptr.move_as_ok();
2186 LOG(INFO) << "Receive result for LeaveChannelQuery: " << to_string(ptr);
2187 td_->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_));
2188 }
2189
on_error(Status status)2190 void on_error(Status status) final {
2191 td_->contacts_manager_->on_get_channel_error(channel_id_, status, "LeaveChannelQuery");
2192 promise_.set_error(std::move(status));
2193 td_->updates_manager_->get_difference("LeaveChannelQuery");
2194 }
2195 };
2196
2197 class CanEditChannelCreatorQuery final : public Td::ResultHandler {
2198 Promise<Unit> promise_;
2199
2200 public:
CanEditChannelCreatorQuery(Promise<Unit> && promise)2201 explicit CanEditChannelCreatorQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
2202 }
2203
send()2204 void send() {
2205 auto input_user = td_->contacts_manager_->get_input_user(td_->contacts_manager_->get_my_id());
2206 CHECK(input_user != nullptr);
2207 send_query(G()->net_query_creator().create(telegram_api::channels_editCreator(
2208 telegram_api::make_object<telegram_api::inputChannelEmpty>(), std::move(input_user),
2209 make_tl_object<telegram_api::inputCheckPasswordEmpty>())));
2210 }
2211
on_result(BufferSlice packet)2212 void on_result(BufferSlice packet) final {
2213 auto result_ptr = fetch_result<telegram_api::channels_editCreator>(packet);
2214 if (result_ptr.is_error()) {
2215 return on_error(result_ptr.move_as_error());
2216 }
2217
2218 auto ptr = result_ptr.move_as_ok();
2219 LOG(ERROR) << "Receive result for CanEditChannelCreatorQuery: " << to_string(ptr);
2220 promise_.set_error(Status::Error(500, "Server doesn't returned error"));
2221 }
2222
on_error(Status status)2223 void on_error(Status status) final {
2224 promise_.set_error(std::move(status));
2225 }
2226 };
2227
2228 class EditChannelCreatorQuery final : public Td::ResultHandler {
2229 Promise<Unit> promise_;
2230 ChannelId channel_id_;
2231
2232 public:
EditChannelCreatorQuery(Promise<Unit> && promise)2233 explicit EditChannelCreatorQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
2234 }
2235
send(ChannelId channel_id,UserId user_id,tl_object_ptr<telegram_api::InputCheckPasswordSRP> input_check_password)2236 void send(ChannelId channel_id, UserId user_id,
2237 tl_object_ptr<telegram_api::InputCheckPasswordSRP> input_check_password) {
2238 channel_id_ = channel_id;
2239 auto input_channel = td_->contacts_manager_->get_input_channel(channel_id);
2240 if (input_channel == nullptr) {
2241 return promise_.set_error(Status::Error(400, "Have no access to the chat"));
2242 }
2243 auto input_user = td_->contacts_manager_->get_input_user(user_id);
2244 if (input_user == nullptr) {
2245 return promise_.set_error(Status::Error(400, "Have no access to the user"));
2246 }
2247 send_query(G()->net_query_creator().create(telegram_api::channels_editCreator(
2248 std::move(input_channel), std::move(input_user), std::move(input_check_password))));
2249 }
2250
on_result(BufferSlice packet)2251 void on_result(BufferSlice packet) final {
2252 auto result_ptr = fetch_result<telegram_api::channels_editCreator>(packet);
2253 if (result_ptr.is_error()) {
2254 return on_error(result_ptr.move_as_error());
2255 }
2256
2257 auto ptr = result_ptr.move_as_ok();
2258 LOG(INFO) << "Receive result for EditChannelCreatorQuery: " << to_string(ptr);
2259 td_->contacts_manager_->invalidate_channel_full(channel_id_, false);
2260 td_->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_));
2261 }
2262
on_error(Status status)2263 void on_error(Status status) final {
2264 td_->contacts_manager_->on_get_channel_error(channel_id_, status, "EditChannelCreatorQuery");
2265 promise_.set_error(std::move(status));
2266 td_->updates_manager_->get_difference("EditChannelCreatorQuery");
2267 }
2268 };
2269
2270 class MigrateChatQuery final : public Td::ResultHandler {
2271 Promise<Unit> promise_;
2272
2273 public:
MigrateChatQuery(Promise<Unit> && promise)2274 explicit MigrateChatQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
2275 }
2276
send(ChatId chat_id)2277 void send(ChatId chat_id) {
2278 send_query(G()->net_query_creator().create(telegram_api::messages_migrateChat(chat_id.get())));
2279 }
2280
on_result(BufferSlice packet)2281 void on_result(BufferSlice packet) final {
2282 auto result_ptr = fetch_result<telegram_api::messages_migrateChat>(packet);
2283 if (result_ptr.is_error()) {
2284 return on_error(result_ptr.move_as_error());
2285 }
2286
2287 auto ptr = result_ptr.move_as_ok();
2288 LOG(INFO) << "Receive result for MigrateChatQuery: " << to_string(ptr);
2289 td_->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_));
2290 }
2291
on_error(Status status)2292 void on_error(Status status) final {
2293 promise_.set_error(std::move(status));
2294 td_->updates_manager_->get_difference("MigrateChatQuery");
2295 }
2296 };
2297
2298 class GetCreatedPublicChannelsQuery final : public Td::ResultHandler {
2299 Promise<Unit> promise_;
2300 PublicDialogType type_;
2301
2302 public:
GetCreatedPublicChannelsQuery(Promise<Unit> && promise)2303 explicit GetCreatedPublicChannelsQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
2304 }
2305
send(PublicDialogType type,bool check_limit)2306 void send(PublicDialogType type, bool check_limit) {
2307 type_ = type;
2308 int32 flags = 0;
2309 if (type_ == PublicDialogType::IsLocationBased) {
2310 flags |= telegram_api::channels_getAdminedPublicChannels::BY_LOCATION_MASK;
2311 }
2312 if (check_limit) {
2313 flags |= telegram_api::channels_getAdminedPublicChannels::CHECK_LIMIT_MASK;
2314 }
2315 send_query(G()->net_query_creator().create(
2316 telegram_api::channels_getAdminedPublicChannels(flags, false /*ignored*/, false /*ignored*/)));
2317 }
2318
on_result(BufferSlice packet)2319 void on_result(BufferSlice packet) final {
2320 auto result_ptr = fetch_result<telegram_api::channels_getAdminedPublicChannels>(packet);
2321 if (result_ptr.is_error()) {
2322 return on_error(result_ptr.move_as_error());
2323 }
2324
2325 auto chats_ptr = result_ptr.move_as_ok();
2326 LOG(INFO) << "Receive result for GetCreatedPublicChannelsQuery: " << to_string(chats_ptr);
2327 int32 constructor_id = chats_ptr->get_id();
2328 switch (constructor_id) {
2329 case telegram_api::messages_chats::ID: {
2330 auto chats = move_tl_object_as<telegram_api::messages_chats>(chats_ptr);
2331 td_->contacts_manager_->on_get_created_public_channels(type_, std::move(chats->chats_));
2332 break;
2333 }
2334 case telegram_api::messages_chatsSlice::ID: {
2335 auto chats = move_tl_object_as<telegram_api::messages_chatsSlice>(chats_ptr);
2336 LOG(ERROR) << "Receive chatsSlice in result of GetCreatedPublicChannelsQuery";
2337 td_->contacts_manager_->on_get_created_public_channels(type_, std::move(chats->chats_));
2338 break;
2339 }
2340 default:
2341 UNREACHABLE();
2342 }
2343
2344 promise_.set_value(Unit());
2345 }
2346
on_error(Status status)2347 void on_error(Status status) final {
2348 promise_.set_error(std::move(status));
2349 }
2350 };
2351
2352 class GetGroupsForDiscussionQuery final : public Td::ResultHandler {
2353 Promise<Unit> promise_;
2354
2355 public:
GetGroupsForDiscussionQuery(Promise<Unit> && promise)2356 explicit GetGroupsForDiscussionQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
2357 }
2358
send()2359 void send() {
2360 send_query(G()->net_query_creator().create(telegram_api::channels_getGroupsForDiscussion()));
2361 }
2362
on_result(BufferSlice packet)2363 void on_result(BufferSlice packet) final {
2364 auto result_ptr = fetch_result<telegram_api::channels_getGroupsForDiscussion>(packet);
2365 if (result_ptr.is_error()) {
2366 return on_error(result_ptr.move_as_error());
2367 }
2368
2369 auto chats_ptr = result_ptr.move_as_ok();
2370 LOG(INFO) << "Receive result for GetGroupsForDiscussionQuery: " << to_string(chats_ptr);
2371 int32 constructor_id = chats_ptr->get_id();
2372 switch (constructor_id) {
2373 case telegram_api::messages_chats::ID: {
2374 auto chats = move_tl_object_as<telegram_api::messages_chats>(chats_ptr);
2375 td_->contacts_manager_->on_get_dialogs_for_discussion(std::move(chats->chats_));
2376 break;
2377 }
2378 case telegram_api::messages_chatsSlice::ID: {
2379 auto chats = move_tl_object_as<telegram_api::messages_chatsSlice>(chats_ptr);
2380 LOG(ERROR) << "Receive chatsSlice in result of GetGroupsForDiscussionQuery";
2381 td_->contacts_manager_->on_get_dialogs_for_discussion(std::move(chats->chats_));
2382 break;
2383 }
2384 default:
2385 UNREACHABLE();
2386 }
2387
2388 promise_.set_value(Unit());
2389 }
2390
on_error(Status status)2391 void on_error(Status status) final {
2392 promise_.set_error(std::move(status));
2393 }
2394 };
2395
2396 class GetInactiveChannelsQuery final : public Td::ResultHandler {
2397 Promise<Unit> promise_;
2398
2399 public:
GetInactiveChannelsQuery(Promise<Unit> && promise)2400 explicit GetInactiveChannelsQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
2401 }
2402
send()2403 void send() {
2404 send_query(G()->net_query_creator().create(telegram_api::channels_getInactiveChannels()));
2405 }
2406
on_result(BufferSlice packet)2407 void on_result(BufferSlice packet) final {
2408 auto result_ptr = fetch_result<telegram_api::channels_getInactiveChannels>(packet);
2409 if (result_ptr.is_error()) {
2410 return on_error(result_ptr.move_as_error());
2411 }
2412
2413 auto result = result_ptr.move_as_ok();
2414 LOG(INFO) << "Receive result for GetInactiveChannelsQuery: " << to_string(result);
2415 // TODO use result->dates_
2416 td_->contacts_manager_->on_get_users(std::move(result->users_), "GetInactiveChannelsQuery");
2417 td_->contacts_manager_->on_get_inactive_channels(std::move(result->chats_));
2418
2419 promise_.set_value(Unit());
2420 }
2421
on_error(Status status)2422 void on_error(Status status) final {
2423 promise_.set_error(std::move(status));
2424 }
2425 };
2426
2427 class GetUsersQuery final : public Td::ResultHandler {
2428 Promise<Unit> promise_;
2429
2430 public:
GetUsersQuery(Promise<Unit> && promise)2431 explicit GetUsersQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
2432 }
2433
send(vector<tl_object_ptr<telegram_api::InputUser>> && input_users)2434 void send(vector<tl_object_ptr<telegram_api::InputUser>> &&input_users) {
2435 send_query(G()->net_query_creator().create(telegram_api::users_getUsers(std::move(input_users))));
2436 }
2437
on_result(BufferSlice packet)2438 void on_result(BufferSlice packet) final {
2439 auto result_ptr = fetch_result<telegram_api::users_getUsers>(packet);
2440 if (result_ptr.is_error()) {
2441 return on_error(result_ptr.move_as_error());
2442 }
2443
2444 td_->contacts_manager_->on_get_users(result_ptr.move_as_ok(), "GetUsersQuery");
2445
2446 promise_.set_value(Unit());
2447 }
2448
on_error(Status status)2449 void on_error(Status status) final {
2450 promise_.set_error(std::move(status));
2451 }
2452 };
2453
2454 class GetFullUserQuery final : public Td::ResultHandler {
2455 Promise<Unit> promise_;
2456
2457 public:
GetFullUserQuery(Promise<Unit> && promise)2458 explicit GetFullUserQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
2459 }
2460
send(tl_object_ptr<telegram_api::InputUser> && input_user)2461 void send(tl_object_ptr<telegram_api::InputUser> &&input_user) {
2462 send_query(G()->net_query_creator().create(telegram_api::users_getFullUser(std::move(input_user))));
2463 }
2464
on_result(BufferSlice packet)2465 void on_result(BufferSlice packet) final {
2466 auto result_ptr = fetch_result<telegram_api::users_getFullUser>(packet);
2467 if (result_ptr.is_error()) {
2468 return on_error(result_ptr.move_as_error());
2469 }
2470
2471 auto ptr = result_ptr.move_as_ok();
2472 LOG(DEBUG) << "Receive result for GetFullUserQuery: " << to_string(ptr);
2473 td_->contacts_manager_->on_get_users(std::move(ptr->users_), "GetFullUserQuery");
2474 td_->contacts_manager_->on_get_chats(std::move(ptr->chats_), "GetFullUserQuery");
2475 td_->contacts_manager_->on_get_user_full(std::move(ptr->full_user_));
2476 promise_.set_value(Unit());
2477 }
2478
on_error(Status status)2479 void on_error(Status status) final {
2480 promise_.set_error(std::move(status));
2481 }
2482 };
2483
2484 class GetUserPhotosQuery final : public Td::ResultHandler {
2485 Promise<Unit> promise_;
2486 UserId user_id_;
2487 int32 offset_;
2488 int32 limit_;
2489
2490 public:
GetUserPhotosQuery(Promise<Unit> && promise)2491 explicit GetUserPhotosQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
2492 }
2493
send(UserId user_id,tl_object_ptr<telegram_api::InputUser> && input_user,int32 offset,int32 limit,int64 photo_id)2494 void send(UserId user_id, tl_object_ptr<telegram_api::InputUser> &&input_user, int32 offset, int32 limit,
2495 int64 photo_id) {
2496 user_id_ = user_id;
2497 offset_ = offset;
2498 limit_ = limit;
2499 send_query(G()->net_query_creator().create(
2500 telegram_api::photos_getUserPhotos(std::move(input_user), offset, photo_id, limit)));
2501 }
2502
on_result(BufferSlice packet)2503 void on_result(BufferSlice packet) final {
2504 auto result_ptr = fetch_result<telegram_api::photos_getUserPhotos>(packet);
2505 if (result_ptr.is_error()) {
2506 return on_error(result_ptr.move_as_error());
2507 }
2508
2509 auto ptr = result_ptr.move_as_ok();
2510
2511 LOG(INFO) << "Receive result for GetUserPhotosQuery: " << to_string(ptr);
2512 int32 constructor_id = ptr->get_id();
2513 if (constructor_id == telegram_api::photos_photos::ID) {
2514 auto photos = move_tl_object_as<telegram_api::photos_photos>(ptr);
2515
2516 td_->contacts_manager_->on_get_users(std::move(photos->users_), "GetUserPhotosQuery");
2517 auto photos_size = narrow_cast<int32>(photos->photos_.size());
2518 td_->contacts_manager_->on_get_user_photos(user_id_, offset_, limit_, photos_size, std::move(photos->photos_));
2519 } else {
2520 CHECK(constructor_id == telegram_api::photos_photosSlice::ID);
2521 auto photos = move_tl_object_as<telegram_api::photos_photosSlice>(ptr);
2522
2523 td_->contacts_manager_->on_get_users(std::move(photos->users_), "GetUserPhotosQuery");
2524 td_->contacts_manager_->on_get_user_photos(user_id_, offset_, limit_, photos->count_, std::move(photos->photos_));
2525 }
2526
2527 promise_.set_value(Unit());
2528 }
2529
on_error(Status status)2530 void on_error(Status status) final {
2531 promise_.set_error(std::move(status));
2532 }
2533 };
2534
2535 class GetChatsQuery final : public Td::ResultHandler {
2536 Promise<Unit> promise_;
2537
2538 public:
GetChatsQuery(Promise<Unit> && promise)2539 explicit GetChatsQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
2540 }
2541
send(vector<int64> && chat_ids)2542 void send(vector<int64> &&chat_ids) {
2543 send_query(G()->net_query_creator().create(telegram_api::messages_getChats(std::move(chat_ids))));
2544 }
2545
on_result(BufferSlice packet)2546 void on_result(BufferSlice packet) final {
2547 auto result_ptr = fetch_result<telegram_api::messages_getChats>(packet);
2548 if (result_ptr.is_error()) {
2549 return on_error(result_ptr.move_as_error());
2550 }
2551
2552 auto chats_ptr = result_ptr.move_as_ok();
2553 int32 constructor_id = chats_ptr->get_id();
2554 switch (constructor_id) {
2555 case telegram_api::messages_chats::ID: {
2556 auto chats = move_tl_object_as<telegram_api::messages_chats>(chats_ptr);
2557 td_->contacts_manager_->on_get_chats(std::move(chats->chats_), "GetChatsQuery");
2558 break;
2559 }
2560 case telegram_api::messages_chatsSlice::ID: {
2561 auto chats = move_tl_object_as<telegram_api::messages_chatsSlice>(chats_ptr);
2562 LOG(ERROR) << "Receive chatsSlice in result of GetChatsQuery";
2563 td_->contacts_manager_->on_get_chats(std::move(chats->chats_), "GetChatsQuery");
2564 break;
2565 }
2566 default:
2567 UNREACHABLE();
2568 }
2569
2570 promise_.set_value(Unit());
2571 }
2572
on_error(Status status)2573 void on_error(Status status) final {
2574 promise_.set_error(std::move(status));
2575 }
2576 };
2577
2578 class GetFullChatQuery final : public Td::ResultHandler {
2579 Promise<Unit> promise_;
2580 ChatId chat_id_;
2581
2582 public:
GetFullChatQuery(Promise<Unit> && promise)2583 explicit GetFullChatQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
2584 }
2585
send(ChatId chat_id)2586 void send(ChatId chat_id) {
2587 send_query(G()->net_query_creator().create(telegram_api::messages_getFullChat(chat_id.get())));
2588 }
2589
on_result(BufferSlice packet)2590 void on_result(BufferSlice packet) final {
2591 auto result_ptr = fetch_result<telegram_api::messages_getFullChat>(packet);
2592 if (result_ptr.is_error()) {
2593 return on_error(result_ptr.move_as_error());
2594 }
2595
2596 auto ptr = result_ptr.move_as_ok();
2597 td_->contacts_manager_->on_get_users(std::move(ptr->users_), "GetFullChatQuery");
2598 td_->contacts_manager_->on_get_chats(std::move(ptr->chats_), "GetFullChatQuery");
2599 td_->contacts_manager_->on_get_chat_full(std::move(ptr->full_chat_), std::move(promise_));
2600 }
2601
on_error(Status status)2602 void on_error(Status status) final {
2603 td_->contacts_manager_->on_get_chat_full_failed(chat_id_);
2604 promise_.set_error(std::move(status));
2605 }
2606 };
2607
2608 class GetChannelsQuery final : public Td::ResultHandler {
2609 Promise<Unit> promise_;
2610 ChannelId channel_id_;
2611
2612 public:
GetChannelsQuery(Promise<Unit> && promise)2613 explicit GetChannelsQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
2614 }
2615
send(tl_object_ptr<telegram_api::InputChannel> && input_channel)2616 void send(tl_object_ptr<telegram_api::InputChannel> &&input_channel) {
2617 CHECK(input_channel != nullptr);
2618 if (input_channel->get_id() == telegram_api::inputChannel::ID) {
2619 channel_id_ = ChannelId(static_cast<const telegram_api::inputChannel *>(input_channel.get())->channel_id_);
2620 }
2621
2622 vector<tl_object_ptr<telegram_api::InputChannel>> input_channels;
2623 input_channels.push_back(std::move(input_channel));
2624 send_query(G()->net_query_creator().create(telegram_api::channels_getChannels(std::move(input_channels))));
2625 }
2626
on_result(BufferSlice packet)2627 void on_result(BufferSlice packet) final {
2628 auto result_ptr = fetch_result<telegram_api::channels_getChannels>(packet);
2629 if (result_ptr.is_error()) {
2630 return on_error(result_ptr.move_as_error());
2631 }
2632
2633 // LOG(INFO) << "Receive result for GetChannelsQuery: " << to_string(result_ptr.ok());
2634 auto chats_ptr = result_ptr.move_as_ok();
2635 int32 constructor_id = chats_ptr->get_id();
2636 switch (constructor_id) {
2637 case telegram_api::messages_chats::ID: {
2638 auto chats = move_tl_object_as<telegram_api::messages_chats>(chats_ptr);
2639 td_->contacts_manager_->on_get_chats(std::move(chats->chats_), "GetChannelsQuery");
2640 break;
2641 }
2642 case telegram_api::messages_chatsSlice::ID: {
2643 auto chats = move_tl_object_as<telegram_api::messages_chatsSlice>(chats_ptr);
2644 LOG(ERROR) << "Receive chatsSlice in result of GetChannelsQuery";
2645 td_->contacts_manager_->on_get_chats(std::move(chats->chats_), "GetChannelsQuery");
2646 break;
2647 }
2648 default:
2649 UNREACHABLE();
2650 }
2651
2652 promise_.set_value(Unit());
2653 }
2654
on_error(Status status)2655 void on_error(Status status) final {
2656 td_->contacts_manager_->on_get_channel_error(channel_id_, status, "GetChannelsQuery");
2657 promise_.set_error(std::move(status));
2658 }
2659 };
2660
2661 class GetFullChannelQuery final : public Td::ResultHandler {
2662 Promise<Unit> promise_;
2663 ChannelId channel_id_;
2664
2665 public:
GetFullChannelQuery(Promise<Unit> && promise)2666 explicit GetFullChannelQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
2667 }
2668
send(ChannelId channel_id,tl_object_ptr<telegram_api::InputChannel> && input_channel)2669 void send(ChannelId channel_id, tl_object_ptr<telegram_api::InputChannel> &&input_channel) {
2670 channel_id_ = channel_id;
2671 send_query(G()->net_query_creator().create(telegram_api::channels_getFullChannel(std::move(input_channel))));
2672 }
2673
on_result(BufferSlice packet)2674 void on_result(BufferSlice packet) final {
2675 auto result_ptr = fetch_result<telegram_api::channels_getFullChannel>(packet);
2676 if (result_ptr.is_error()) {
2677 return on_error(result_ptr.move_as_error());
2678 }
2679
2680 auto ptr = result_ptr.move_as_ok();
2681 td_->contacts_manager_->on_get_users(std::move(ptr->users_), "GetFullChannelQuery");
2682 td_->contacts_manager_->on_get_chats(std::move(ptr->chats_), "GetFullChannelQuery");
2683 td_->contacts_manager_->on_get_chat_full(std::move(ptr->full_chat_), std::move(promise_));
2684 }
2685
on_error(Status status)2686 void on_error(Status status) final {
2687 td_->contacts_manager_->on_get_channel_error(channel_id_, status, "GetFullChannelQuery");
2688 td_->contacts_manager_->on_get_channel_full_failed(channel_id_);
2689 promise_.set_error(std::move(status));
2690 }
2691 };
2692
2693 class GetChannelParticipantQuery final : public Td::ResultHandler {
2694 Promise<DialogParticipant> promise_;
2695 ChannelId channel_id_;
2696 DialogId participant_dialog_id_;
2697
2698 public:
GetChannelParticipantQuery(Promise<DialogParticipant> && promise)2699 explicit GetChannelParticipantQuery(Promise<DialogParticipant> &&promise) : promise_(std::move(promise)) {
2700 }
2701
send(ChannelId channel_id,DialogId participant_dialog_id,tl_object_ptr<telegram_api::InputPeer> && input_peer)2702 void send(ChannelId channel_id, DialogId participant_dialog_id, tl_object_ptr<telegram_api::InputPeer> &&input_peer) {
2703 auto input_channel = td_->contacts_manager_->get_input_channel(channel_id);
2704 if (input_channel == nullptr) {
2705 return promise_.set_error(Status::Error(400, "Supergroup not found"));
2706 }
2707
2708 CHECK(input_peer != nullptr);
2709
2710 channel_id_ = channel_id;
2711 participant_dialog_id_ = participant_dialog_id;
2712 send_query(G()->net_query_creator().create(
2713 telegram_api::channels_getParticipant(std::move(input_channel), std::move(input_peer))));
2714 }
2715
on_result(BufferSlice packet)2716 void on_result(BufferSlice packet) final {
2717 auto result_ptr = fetch_result<telegram_api::channels_getParticipant>(packet);
2718 if (result_ptr.is_error()) {
2719 return on_error(result_ptr.move_as_error());
2720 }
2721
2722 auto participant = result_ptr.move_as_ok();
2723 LOG(INFO) << "Receive result for GetChannelParticipantQuery: " << to_string(participant);
2724
2725 td_->contacts_manager_->on_get_users(std::move(participant->users_), "GetChannelParticipantQuery");
2726 td_->contacts_manager_->on_get_chats(std::move(participant->chats_), "GetChannelParticipantQuery");
2727 DialogParticipant result(std::move(participant->participant_));
2728 if (!result.is_valid()) {
2729 LOG(ERROR) << "Receive invalid " << result;
2730 return promise_.set_error(Status::Error(500, "Receive invalid chat member"));
2731 }
2732 promise_.set_value(std::move(result));
2733 }
2734
on_error(Status status)2735 void on_error(Status status) final {
2736 if (status.message() == "USER_NOT_PARTICIPANT") {
2737 promise_.set_value(DialogParticipant::left(participant_dialog_id_));
2738 return;
2739 }
2740
2741 // td_->contacts_manager_->on_get_channel_error(channel_id_, status, "GetChannelParticipantQuery");
2742 promise_.set_error(std::move(status));
2743 }
2744 };
2745
2746 class GetChannelParticipantsQuery final : public Td::ResultHandler {
2747 Promise<tl_object_ptr<telegram_api::channels_channelParticipants>> promise_;
2748 ChannelId channel_id_;
2749
2750 public:
GetChannelParticipantsQuery(Promise<tl_object_ptr<telegram_api::channels_channelParticipants>> && promise)2751 explicit GetChannelParticipantsQuery(Promise<tl_object_ptr<telegram_api::channels_channelParticipants>> &&promise)
2752 : promise_(std::move(promise)) {
2753 }
2754
send(ChannelId channel_id,const ChannelParticipantsFilter & filter,int32 offset,int32 limit)2755 void send(ChannelId channel_id, const ChannelParticipantsFilter &filter, int32 offset, int32 limit) {
2756 auto input_channel = td_->contacts_manager_->get_input_channel(channel_id);
2757 if (input_channel == nullptr) {
2758 return promise_.set_error(Status::Error(400, "Supergroup not found"));
2759 }
2760
2761 channel_id_ = channel_id;
2762 send_query(G()->net_query_creator().create(telegram_api::channels_getParticipants(
2763 std::move(input_channel), filter.get_input_channel_participants_filter(), offset, limit, 0)));
2764 }
2765
on_result(BufferSlice packet)2766 void on_result(BufferSlice packet) final {
2767 auto result_ptr = fetch_result<telegram_api::channels_getParticipants>(packet);
2768 if (result_ptr.is_error()) {
2769 return on_error(result_ptr.move_as_error());
2770 }
2771
2772 auto participants_ptr = result_ptr.move_as_ok();
2773 LOG(INFO) << "Receive result for GetChannelParticipantsQuery: " << to_string(participants_ptr);
2774 switch (participants_ptr->get_id()) {
2775 case telegram_api::channels_channelParticipants::ID: {
2776 promise_.set_value(telegram_api::move_object_as<telegram_api::channels_channelParticipants>(participants_ptr));
2777 break;
2778 }
2779 case telegram_api::channels_channelParticipantsNotModified::ID:
2780 LOG(ERROR) << "Receive channelParticipantsNotModified";
2781 return on_error(Status::Error(500, "Receive channelParticipantsNotModified"));
2782 default:
2783 UNREACHABLE();
2784 }
2785 }
2786
on_error(Status status)2787 void on_error(Status status) final {
2788 td_->contacts_manager_->on_get_channel_error(channel_id_, status, "GetChannelParticipantsQuery");
2789 promise_.set_error(std::move(status));
2790 }
2791 };
2792
2793 class GetChannelAdministratorsQuery final : public Td::ResultHandler {
2794 Promise<Unit> promise_;
2795 ChannelId channel_id_;
2796
2797 public:
GetChannelAdministratorsQuery(Promise<Unit> && promise)2798 explicit GetChannelAdministratorsQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
2799 }
2800
send(ChannelId channel_id,int64 hash)2801 void send(ChannelId channel_id, int64 hash) {
2802 auto input_channel = td_->contacts_manager_->get_input_channel(channel_id);
2803 if (input_channel == nullptr) {
2804 return promise_.set_error(Status::Error(400, "Supergroup not found"));
2805 }
2806
2807 hash = 0; // to load even only ranks or creator changed
2808
2809 channel_id_ = channel_id;
2810 send_query(G()->net_query_creator().create(telegram_api::channels_getParticipants(
2811 std::move(input_channel), telegram_api::make_object<telegram_api::channelParticipantsAdmins>(), 0,
2812 std::numeric_limits<int32>::max(), hash)));
2813 }
2814
on_result(BufferSlice packet)2815 void on_result(BufferSlice packet) final {
2816 auto result_ptr = fetch_result<telegram_api::channels_getParticipants>(packet);
2817 if (result_ptr.is_error()) {
2818 return on_error(result_ptr.move_as_error());
2819 }
2820
2821 auto participants_ptr = result_ptr.move_as_ok();
2822 LOG(INFO) << "Receive result for GetChannelAdministratorsQuery: " << to_string(participants_ptr);
2823 switch (participants_ptr->get_id()) {
2824 case telegram_api::channels_channelParticipants::ID: {
2825 auto participants = telegram_api::move_object_as<telegram_api::channels_channelParticipants>(participants_ptr);
2826 td_->contacts_manager_->on_get_users(std::move(participants->users_), "GetChannelAdministratorsQuery");
2827 td_->contacts_manager_->on_get_chats(std::move(participants->chats_), "GetChannelAdministratorsQuery");
2828 vector<DialogAdministrator> administrators;
2829 administrators.reserve(participants->participants_.size());
2830 for (auto &participant : participants->participants_) {
2831 DialogParticipant dialog_participant(std::move(participant));
2832 if (!dialog_participant.is_valid() || !dialog_participant.status_.is_administrator() ||
2833 dialog_participant.dialog_id_.get_type() != DialogType::User) {
2834 LOG(ERROR) << "Receive " << dialog_participant << " as an administrator of " << channel_id_;
2835 continue;
2836 }
2837 administrators.emplace_back(dialog_participant.dialog_id_.get_user_id(),
2838 dialog_participant.status_.get_rank(), dialog_participant.status_.is_creator());
2839 }
2840
2841 td_->contacts_manager_->on_update_channel_administrator_count(channel_id_,
2842 narrow_cast<int32>(administrators.size()));
2843 td_->contacts_manager_->on_update_dialog_administrators(DialogId(channel_id_), std::move(administrators), true,
2844 false);
2845
2846 break;
2847 }
2848 case telegram_api::channels_channelParticipantsNotModified::ID:
2849 break;
2850 default:
2851 UNREACHABLE();
2852 }
2853
2854 promise_.set_value(Unit());
2855 }
2856
on_error(Status status)2857 void on_error(Status status) final {
2858 td_->contacts_manager_->on_get_channel_error(channel_id_, status, "GetChannelAdministratorsQuery");
2859 promise_.set_error(std::move(status));
2860 }
2861 };
2862
2863 class GetSupportUserQuery final : public Td::ResultHandler {
2864 Promise<Unit> promise_;
2865
2866 public:
GetSupportUserQuery(Promise<Unit> && promise)2867 explicit GetSupportUserQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
2868 }
2869
send()2870 void send() {
2871 send_query(G()->net_query_creator().create(telegram_api::help_getSupport()));
2872 }
2873
on_result(BufferSlice packet)2874 void on_result(BufferSlice packet) final {
2875 auto result_ptr = fetch_result<telegram_api::help_getSupport>(packet);
2876 if (result_ptr.is_error()) {
2877 return on_error(result_ptr.move_as_error());
2878 }
2879
2880 auto ptr = result_ptr.move_as_ok();
2881 LOG(INFO) << "Receive result for GetSupportUserQuery: " << to_string(ptr);
2882
2883 td_->contacts_manager_->on_get_user(std::move(ptr->user_), "GetSupportUserQuery", false, true);
2884
2885 promise_.set_value(Unit());
2886 }
2887
on_error(Status status)2888 void on_error(Status status) final {
2889 promise_.set_error(std::move(status));
2890 }
2891 };
2892
convert_date_range(const tl_object_ptr<telegram_api::statsDateRangeDays> & obj)2893 tl_object_ptr<td_api::dateRange> ContactsManager::convert_date_range(
2894 const tl_object_ptr<telegram_api::statsDateRangeDays> &obj) {
2895 return make_tl_object<td_api::dateRange>(obj->min_date_, obj->max_date_);
2896 }
2897
convert_stats_graph(tl_object_ptr<telegram_api::StatsGraph> obj)2898 tl_object_ptr<td_api::StatisticalGraph> ContactsManager::convert_stats_graph(
2899 tl_object_ptr<telegram_api::StatsGraph> obj) {
2900 CHECK(obj != nullptr);
2901
2902 switch (obj->get_id()) {
2903 case telegram_api::statsGraphAsync::ID: {
2904 auto graph = move_tl_object_as<telegram_api::statsGraphAsync>(obj);
2905 return make_tl_object<td_api::statisticalGraphAsync>(std::move(graph->token_));
2906 }
2907 case telegram_api::statsGraphError::ID: {
2908 auto graph = move_tl_object_as<telegram_api::statsGraphError>(obj);
2909 return make_tl_object<td_api::statisticalGraphError>(std::move(graph->error_));
2910 }
2911 case telegram_api::statsGraph::ID: {
2912 auto graph = move_tl_object_as<telegram_api::statsGraph>(obj);
2913 return make_tl_object<td_api::statisticalGraphData>(std::move(graph->json_->data_),
2914 std::move(graph->zoom_token_));
2915 }
2916 default:
2917 UNREACHABLE();
2918 return nullptr;
2919 }
2920 }
2921
get_percentage_value(double part,double total)2922 double ContactsManager::get_percentage_value(double part, double total) {
2923 if (total < 1e-6 && total > -1e-6) {
2924 if (part < 1e-6 && part > -1e-6) {
2925 return 0.0;
2926 }
2927 return 100.0;
2928 }
2929 if (part > 1e20) {
2930 return 100.0;
2931 }
2932 return part / total * 100;
2933 }
2934
convert_stats_absolute_value(const tl_object_ptr<telegram_api::statsAbsValueAndPrev> & obj)2935 tl_object_ptr<td_api::statisticalValue> ContactsManager::convert_stats_absolute_value(
2936 const tl_object_ptr<telegram_api::statsAbsValueAndPrev> &obj) {
2937 return make_tl_object<td_api::statisticalValue>(obj->current_, obj->previous_,
2938 get_percentage_value(obj->current_ - obj->previous_, obj->previous_));
2939 }
2940
convert_megagroup_stats(tl_object_ptr<telegram_api::stats_megagroupStats> obj)2941 tl_object_ptr<td_api::chatStatisticsSupergroup> ContactsManager::convert_megagroup_stats(
2942 tl_object_ptr<telegram_api::stats_megagroupStats> obj) {
2943 CHECK(obj != nullptr);
2944
2945 on_get_users(std::move(obj->users_), "convert_megagroup_stats");
2946
2947 // just in case
2948 td::remove_if(obj->top_posters_, [](auto &obj) {
2949 return !UserId(obj->user_id_).is_valid() || obj->messages_ < 0 || obj->avg_chars_ < 0;
2950 });
2951 td::remove_if(obj->top_admins_, [](auto &obj) {
2952 return !UserId(obj->user_id_).is_valid() || obj->deleted_ < 0 || obj->kicked_ < 0 || obj->banned_ < 0;
2953 });
2954 td::remove_if(obj->top_inviters_,
2955 [](auto &obj) { return !UserId(obj->user_id_).is_valid() || obj->invitations_ < 0; });
2956
2957 auto top_senders =
2958 transform(std::move(obj->top_posters_), [this](tl_object_ptr<telegram_api::statsGroupTopPoster> &&top_poster) {
2959 return td_api::make_object<td_api::chatStatisticsMessageSenderInfo>(
2960 get_user_id_object(UserId(top_poster->user_id_), "get_top_senders"), top_poster->messages_,
2961 top_poster->avg_chars_);
2962 });
2963 auto top_administrators =
2964 transform(std::move(obj->top_admins_), [this](tl_object_ptr<telegram_api::statsGroupTopAdmin> &&top_admin) {
2965 return td_api::make_object<td_api::chatStatisticsAdministratorActionsInfo>(
2966 get_user_id_object(UserId(top_admin->user_id_), "get_top_administrators"), top_admin->deleted_,
2967 top_admin->kicked_, top_admin->banned_);
2968 });
2969 auto top_inviters =
2970 transform(std::move(obj->top_inviters_), [this](tl_object_ptr<telegram_api::statsGroupTopInviter> &&top_inviter) {
2971 return td_api::make_object<td_api::chatStatisticsInviterInfo>(
2972 get_user_id_object(UserId(top_inviter->user_id_), "get_top_inviters"), top_inviter->invitations_);
2973 });
2974
2975 return make_tl_object<td_api::chatStatisticsSupergroup>(
2976 convert_date_range(obj->period_), convert_stats_absolute_value(obj->members_),
2977 convert_stats_absolute_value(obj->messages_), convert_stats_absolute_value(obj->viewers_),
2978 convert_stats_absolute_value(obj->posters_), convert_stats_graph(std::move(obj->growth_graph_)),
2979 convert_stats_graph(std::move(obj->members_graph_)),
2980 convert_stats_graph(std::move(obj->new_members_by_source_graph_)),
2981 convert_stats_graph(std::move(obj->languages_graph_)), convert_stats_graph(std::move(obj->messages_graph_)),
2982 convert_stats_graph(std::move(obj->actions_graph_)), convert_stats_graph(std::move(obj->top_hours_graph_)),
2983 convert_stats_graph(std::move(obj->weekdays_graph_)), std::move(top_senders), std::move(top_administrators),
2984 std::move(top_inviters));
2985 }
2986
convert_broadcast_stats(tl_object_ptr<telegram_api::stats_broadcastStats> obj)2987 tl_object_ptr<td_api::chatStatisticsChannel> ContactsManager::convert_broadcast_stats(
2988 tl_object_ptr<telegram_api::stats_broadcastStats> obj) {
2989 CHECK(obj != nullptr);
2990
2991 auto recent_message_interactions = transform(std::move(obj->recent_message_interactions_), [](auto &&interaction) {
2992 return make_tl_object<td_api::chatStatisticsMessageInteractionInfo>(
2993 MessageId(ServerMessageId(interaction->msg_id_)).get(), interaction->views_, interaction->forwards_);
2994 });
2995
2996 return make_tl_object<td_api::chatStatisticsChannel>(
2997 convert_date_range(obj->period_), convert_stats_absolute_value(obj->followers_),
2998 convert_stats_absolute_value(obj->views_per_post_), convert_stats_absolute_value(obj->shares_per_post_),
2999 get_percentage_value(obj->enabled_notifications_->part_, obj->enabled_notifications_->total_),
3000 convert_stats_graph(std::move(obj->growth_graph_)), convert_stats_graph(std::move(obj->followers_graph_)),
3001 convert_stats_graph(std::move(obj->mute_graph_)), convert_stats_graph(std::move(obj->top_hours_graph_)),
3002 convert_stats_graph(std::move(obj->views_by_source_graph_)),
3003 convert_stats_graph(std::move(obj->new_followers_by_source_graph_)),
3004 convert_stats_graph(std::move(obj->languages_graph_)), convert_stats_graph(std::move(obj->interactions_graph_)),
3005 convert_stats_graph(std::move(obj->iv_interactions_graph_)), std::move(recent_message_interactions));
3006 }
3007
3008 class GetMegagroupStatsQuery final : public Td::ResultHandler {
3009 Promise<td_api::object_ptr<td_api::ChatStatistics>> promise_;
3010 ChannelId channel_id_;
3011
3012 public:
GetMegagroupStatsQuery(Promise<td_api::object_ptr<td_api::ChatStatistics>> && promise)3013 explicit GetMegagroupStatsQuery(Promise<td_api::object_ptr<td_api::ChatStatistics>> &&promise)
3014 : promise_(std::move(promise)) {
3015 }
3016
send(ChannelId channel_id,bool is_dark,DcId dc_id)3017 void send(ChannelId channel_id, bool is_dark, DcId dc_id) {
3018 channel_id_ = channel_id;
3019
3020 auto input_channel = td_->contacts_manager_->get_input_channel(channel_id);
3021 CHECK(input_channel != nullptr);
3022
3023 int32 flags = 0;
3024 if (is_dark) {
3025 flags |= telegram_api::stats_getMegagroupStats::DARK_MASK;
3026 }
3027 send_query(G()->net_query_creator().create(
3028 telegram_api::stats_getMegagroupStats(flags, false /*ignored*/, std::move(input_channel)), dc_id));
3029 }
3030
on_result(BufferSlice packet)3031 void on_result(BufferSlice packet) final {
3032 auto result_ptr = fetch_result<telegram_api::stats_getMegagroupStats>(packet);
3033 if (result_ptr.is_error()) {
3034 return on_error(result_ptr.move_as_error());
3035 }
3036
3037 promise_.set_value(td_->contacts_manager_->convert_megagroup_stats(result_ptr.move_as_ok()));
3038 }
3039
on_error(Status status)3040 void on_error(Status status) final {
3041 td_->contacts_manager_->on_get_channel_error(channel_id_, status, "GetMegagroupStatsQuery");
3042 promise_.set_error(std::move(status));
3043 }
3044 };
3045
3046 class GetBroadcastStatsQuery final : public Td::ResultHandler {
3047 Promise<td_api::object_ptr<td_api::ChatStatistics>> promise_;
3048 ChannelId channel_id_;
3049
3050 public:
GetBroadcastStatsQuery(Promise<td_api::object_ptr<td_api::ChatStatistics>> && promise)3051 explicit GetBroadcastStatsQuery(Promise<td_api::object_ptr<td_api::ChatStatistics>> &&promise)
3052 : promise_(std::move(promise)) {
3053 }
3054
send(ChannelId channel_id,bool is_dark,DcId dc_id)3055 void send(ChannelId channel_id, bool is_dark, DcId dc_id) {
3056 channel_id_ = channel_id;
3057
3058 auto input_channel = td_->contacts_manager_->get_input_channel(channel_id);
3059 CHECK(input_channel != nullptr);
3060
3061 int32 flags = 0;
3062 if (is_dark) {
3063 flags |= telegram_api::stats_getBroadcastStats::DARK_MASK;
3064 }
3065 send_query(G()->net_query_creator().create(
3066 telegram_api::stats_getBroadcastStats(flags, false /*ignored*/, std::move(input_channel)), dc_id));
3067 }
3068
on_result(BufferSlice packet)3069 void on_result(BufferSlice packet) final {
3070 auto result_ptr = fetch_result<telegram_api::stats_getBroadcastStats>(packet);
3071 if (result_ptr.is_error()) {
3072 return on_error(result_ptr.move_as_error());
3073 }
3074
3075 auto result = ContactsManager::convert_broadcast_stats(result_ptr.move_as_ok());
3076 for (auto &info : result->recent_message_interactions_) {
3077 td_->messages_manager_->on_update_message_interaction_info({DialogId(channel_id_), MessageId(info->message_id_)},
3078 info->view_count_, info->forward_count_, false,
3079 nullptr);
3080 }
3081 promise_.set_value(std::move(result));
3082 }
3083
on_error(Status status)3084 void on_error(Status status) final {
3085 td_->contacts_manager_->on_get_channel_error(channel_id_, status, "GetBroadcastStatsQuery");
3086 promise_.set_error(std::move(status));
3087 }
3088 };
3089
convert_message_stats(tl_object_ptr<telegram_api::stats_messageStats> obj)3090 tl_object_ptr<td_api::messageStatistics> ContactsManager::convert_message_stats(
3091 tl_object_ptr<telegram_api::stats_messageStats> obj) {
3092 return make_tl_object<td_api::messageStatistics>(convert_stats_graph(std::move(obj->views_graph_)));
3093 }
3094
3095 class GetMessageStatsQuery final : public Td::ResultHandler {
3096 Promise<td_api::object_ptr<td_api::messageStatistics>> promise_;
3097 ChannelId channel_id_;
3098
3099 public:
GetMessageStatsQuery(Promise<td_api::object_ptr<td_api::messageStatistics>> && promise)3100 explicit GetMessageStatsQuery(Promise<td_api::object_ptr<td_api::messageStatistics>> &&promise)
3101 : promise_(std::move(promise)) {
3102 }
3103
send(ChannelId channel_id,MessageId message_id,bool is_dark,DcId dc_id)3104 void send(ChannelId channel_id, MessageId message_id, bool is_dark, DcId dc_id) {
3105 channel_id_ = channel_id;
3106
3107 auto input_channel = td_->contacts_manager_->get_input_channel(channel_id);
3108 CHECK(input_channel != nullptr);
3109
3110 int32 flags = 0;
3111 if (is_dark) {
3112 flags |= telegram_api::stats_getMessageStats::DARK_MASK;
3113 }
3114 send_query(G()->net_query_creator().create(
3115 telegram_api::stats_getMessageStats(flags, false /*ignored*/, std::move(input_channel),
3116 message_id.get_server_message_id().get()),
3117 dc_id));
3118 }
3119
on_result(BufferSlice packet)3120 void on_result(BufferSlice packet) final {
3121 auto result_ptr = fetch_result<telegram_api::stats_getMessageStats>(packet);
3122 if (result_ptr.is_error()) {
3123 return on_error(result_ptr.move_as_error());
3124 }
3125
3126 promise_.set_value(td_->contacts_manager_->convert_message_stats(result_ptr.move_as_ok()));
3127 }
3128
on_error(Status status)3129 void on_error(Status status) final {
3130 td_->contacts_manager_->on_get_channel_error(channel_id_, status, "GetMessageStatsQuery");
3131 promise_.set_error(std::move(status));
3132 }
3133 };
3134
3135 class LoadAsyncGraphQuery final : public Td::ResultHandler {
3136 Promise<td_api::object_ptr<td_api::StatisticalGraph>> promise_;
3137
3138 public:
LoadAsyncGraphQuery(Promise<td_api::object_ptr<td_api::StatisticalGraph>> && promise)3139 explicit LoadAsyncGraphQuery(Promise<td_api::object_ptr<td_api::StatisticalGraph>> &&promise)
3140 : promise_(std::move(promise)) {
3141 }
3142
send(const string & token,int64 x,DcId dc_id)3143 void send(const string &token, int64 x, DcId dc_id) {
3144 int32 flags = 0;
3145 if (x != 0) {
3146 flags |= telegram_api::stats_loadAsyncGraph::X_MASK;
3147 }
3148 send_query(G()->net_query_creator().create(telegram_api::stats_loadAsyncGraph(flags, token, x), dc_id));
3149 }
3150
on_result(BufferSlice packet)3151 void on_result(BufferSlice packet) final {
3152 auto result_ptr = fetch_result<telegram_api::stats_loadAsyncGraph>(packet);
3153 if (result_ptr.is_error()) {
3154 return on_error(result_ptr.move_as_error());
3155 }
3156
3157 auto result = result_ptr.move_as_ok();
3158 promise_.set_value(ContactsManager::convert_stats_graph(std::move(result)));
3159 }
3160
on_error(Status status)3161 void on_error(Status status) final {
3162 promise_.set_error(std::move(status));
3163 }
3164 };
3165
3166 class ContactsManager::UploadProfilePhotoCallback final : public FileManager::UploadCallback {
3167 public:
on_upload_ok(FileId file_id,tl_object_ptr<telegram_api::InputFile> input_file)3168 void on_upload_ok(FileId file_id, tl_object_ptr<telegram_api::InputFile> input_file) final {
3169 send_closure_later(G()->contacts_manager(), &ContactsManager::on_upload_profile_photo, file_id,
3170 std::move(input_file));
3171 }
on_upload_encrypted_ok(FileId file_id,tl_object_ptr<telegram_api::InputEncryptedFile> input_file)3172 void on_upload_encrypted_ok(FileId file_id, tl_object_ptr<telegram_api::InputEncryptedFile> input_file) final {
3173 UNREACHABLE();
3174 }
on_upload_secure_ok(FileId file_id,tl_object_ptr<telegram_api::InputSecureFile> input_file)3175 void on_upload_secure_ok(FileId file_id, tl_object_ptr<telegram_api::InputSecureFile> input_file) final {
3176 UNREACHABLE();
3177 }
on_upload_error(FileId file_id,Status error)3178 void on_upload_error(FileId file_id, Status error) final {
3179 send_closure_later(G()->contacts_manager(), &ContactsManager::on_upload_profile_photo_error, file_id,
3180 std::move(error));
3181 }
3182 };
3183
ContactsManager(Td * td,ActorShared<> parent)3184 ContactsManager::ContactsManager(Td *td, ActorShared<> parent) : td_(td), parent_(std::move(parent)) {
3185 upload_profile_photo_callback_ = std::make_shared<UploadProfilePhotoCallback>();
3186
3187 my_id_ = load_my_id();
3188
3189 G()->shared_config().set_option_integer("telegram_service_notifications_chat_id",
3190 DialogId(get_service_notifications_user_id()).get());
3191 G()->shared_config().set_option_integer("replies_bot_chat_id", DialogId(get_replies_bot_user_id()).get());
3192 G()->shared_config().set_option_integer("group_anonymous_bot_user_id", get_anonymous_bot_user_id().get());
3193
3194 if (G()->parameters().use_chat_info_db) {
3195 auto next_contacts_sync_date_string = G()->td_db()->get_binlog_pmc()->get("next_contacts_sync_date");
3196 if (!next_contacts_sync_date_string.empty()) {
3197 next_contacts_sync_date_ = min(to_integer<int32>(next_contacts_sync_date_string), G()->unix_time() + 100000);
3198 }
3199
3200 auto saved_contact_count_string = G()->td_db()->get_binlog_pmc()->get("saved_contact_count");
3201 if (!saved_contact_count_string.empty()) {
3202 saved_contact_count_ = to_integer<int32>(saved_contact_count_string);
3203 }
3204 } else {
3205 G()->td_db()->get_binlog_pmc()->erase("next_contacts_sync_date");
3206 G()->td_db()->get_binlog_pmc()->erase("saved_contact_count");
3207 }
3208 if (G()->parameters().use_file_db) {
3209 G()->td_db()->get_sqlite_pmc()->erase_by_prefix("us_bot_info", Auto());
3210 }
3211
3212 was_online_local_ = to_integer<int32>(G()->td_db()->get_binlog_pmc()->get("my_was_online_local"));
3213 was_online_remote_ = to_integer<int32>(G()->td_db()->get_binlog_pmc()->get("my_was_online_remote"));
3214 if (was_online_local_ >= G()->unix_time_cached() && !td_->is_online()) {
3215 was_online_local_ = G()->unix_time_cached() - 1;
3216 }
3217
3218 location_visibility_expire_date_ =
3219 to_integer<int32>(G()->td_db()->get_binlog_pmc()->get("location_visibility_expire_date"));
3220 if (location_visibility_expire_date_ != 0 && location_visibility_expire_date_ <= G()->unix_time()) {
3221 location_visibility_expire_date_ = 0;
3222 G()->td_db()->get_binlog_pmc()->erase("location_visibility_expire_date");
3223 }
3224 auto pending_location_visibility_expire_date_string =
3225 G()->td_db()->get_binlog_pmc()->get("pending_location_visibility_expire_date");
3226 if (!pending_location_visibility_expire_date_string.empty()) {
3227 pending_location_visibility_expire_date_ = to_integer<int32>(pending_location_visibility_expire_date_string);
3228 try_send_set_location_visibility_query();
3229 }
3230 update_is_location_visible();
3231 LOG(INFO) << "Loaded location_visibility_expire_date = " << location_visibility_expire_date_
3232 << " and pending_location_visibility_expire_date = " << pending_location_visibility_expire_date_;
3233
3234 user_online_timeout_.set_callback(on_user_online_timeout_callback);
3235 user_online_timeout_.set_callback_data(static_cast<void *>(this));
3236
3237 channel_unban_timeout_.set_callback(on_channel_unban_timeout_callback);
3238 channel_unban_timeout_.set_callback_data(static_cast<void *>(this));
3239
3240 user_nearby_timeout_.set_callback(on_user_nearby_timeout_callback);
3241 user_nearby_timeout_.set_callback_data(static_cast<void *>(this));
3242
3243 slow_mode_delay_timeout_.set_callback(on_slow_mode_delay_timeout_callback);
3244 slow_mode_delay_timeout_.set_callback_data(static_cast<void *>(this));
3245
3246 invite_link_info_expire_timeout_.set_callback(on_invite_link_info_expire_timeout_callback);
3247 invite_link_info_expire_timeout_.set_callback_data(static_cast<void *>(this));
3248
3249 channel_participant_cache_timeout_.set_callback(on_channel_participant_cache_timeout_callback);
3250 channel_participant_cache_timeout_.set_callback_data(static_cast<void *>(this));
3251 }
3252
3253 ContactsManager::~ContactsManager() = default;
3254
tear_down()3255 void ContactsManager::tear_down() {
3256 parent_.reset();
3257 }
3258
load_my_id()3259 UserId ContactsManager::load_my_id() {
3260 auto id_string = G()->td_db()->get_binlog_pmc()->get("my_id");
3261 if (!id_string.empty()) {
3262 UserId my_id(to_integer<int64>(id_string));
3263 if (my_id.is_valid()) {
3264 return my_id;
3265 }
3266
3267 my_id = UserId(to_integer<int64>(Slice(id_string).substr(5)));
3268 if (my_id.is_valid()) {
3269 G()->td_db()->get_binlog_pmc()->set("my_id", to_string(my_id.get()));
3270 return my_id;
3271 }
3272
3273 LOG(ERROR) << "Wrong my ID = \"" << id_string << "\" stored in database";
3274 }
3275 return UserId();
3276 }
3277
on_user_online_timeout_callback(void * contacts_manager_ptr,int64 user_id_long)3278 void ContactsManager::on_user_online_timeout_callback(void *contacts_manager_ptr, int64 user_id_long) {
3279 if (G()->close_flag()) {
3280 return;
3281 }
3282
3283 auto contacts_manager = static_cast<ContactsManager *>(contacts_manager_ptr);
3284 send_closure_later(contacts_manager->actor_id(contacts_manager), &ContactsManager::on_user_online_timeout,
3285 UserId(user_id_long));
3286 }
3287
on_user_online_timeout(UserId user_id)3288 void ContactsManager::on_user_online_timeout(UserId user_id) {
3289 if (G()->close_flag()) {
3290 return;
3291 }
3292
3293 auto u = get_user(user_id);
3294 CHECK(u != nullptr);
3295 CHECK(u->is_update_user_sent);
3296
3297 LOG(INFO) << "Update " << user_id << " online status to offline";
3298 send_closure(G()->td(), &Td::send_update,
3299 td_api::make_object<td_api::updateUserStatus>(user_id.get(), get_user_status_object(user_id, u)));
3300
3301 update_user_online_member_count(u);
3302 }
3303
on_channel_unban_timeout_callback(void * contacts_manager_ptr,int64 channel_id_long)3304 void ContactsManager::on_channel_unban_timeout_callback(void *contacts_manager_ptr, int64 channel_id_long) {
3305 if (G()->close_flag()) {
3306 return;
3307 }
3308
3309 auto contacts_manager = static_cast<ContactsManager *>(contacts_manager_ptr);
3310 send_closure_later(contacts_manager->actor_id(contacts_manager), &ContactsManager::on_channel_unban_timeout,
3311 ChannelId(channel_id_long));
3312 }
3313
on_channel_unban_timeout(ChannelId channel_id)3314 void ContactsManager::on_channel_unban_timeout(ChannelId channel_id) {
3315 if (G()->close_flag()) {
3316 return;
3317 }
3318
3319 auto c = get_channel(channel_id);
3320 CHECK(c != nullptr);
3321
3322 auto old_status = c->status;
3323 c->status.update_restrictions();
3324 if (c->status == old_status) {
3325 LOG_IF(ERROR, c->status.is_restricted() || c->status.is_banned())
3326 << "Status of " << channel_id << " wasn't updated: " << c->status;
3327 } else {
3328 c->is_changed = true;
3329 }
3330
3331 LOG(INFO) << "Update " << channel_id << " status";
3332 c->is_status_changed = true;
3333 invalidate_channel_full(channel_id, !c->is_slow_mode_enabled);
3334 update_channel(c, channel_id); // always call, because in case of failure we need to reactivate timeout
3335 }
3336
on_user_nearby_timeout_callback(void * contacts_manager_ptr,int64 user_id_long)3337 void ContactsManager::on_user_nearby_timeout_callback(void *contacts_manager_ptr, int64 user_id_long) {
3338 if (G()->close_flag()) {
3339 return;
3340 }
3341
3342 auto contacts_manager = static_cast<ContactsManager *>(contacts_manager_ptr);
3343 send_closure_later(contacts_manager->actor_id(contacts_manager), &ContactsManager::on_user_nearby_timeout,
3344 UserId(user_id_long));
3345 }
3346
on_user_nearby_timeout(UserId user_id)3347 void ContactsManager::on_user_nearby_timeout(UserId user_id) {
3348 if (G()->close_flag()) {
3349 return;
3350 }
3351
3352 auto u = get_user(user_id);
3353 CHECK(u != nullptr);
3354
3355 LOG(INFO) << "Remove " << user_id << " from nearby list";
3356 DialogId dialog_id(user_id);
3357 for (size_t i = 0; i < users_nearby_.size(); i++) {
3358 if (users_nearby_[i].dialog_id == dialog_id) {
3359 users_nearby_.erase(users_nearby_.begin() + i);
3360 send_update_users_nearby();
3361 return;
3362 }
3363 }
3364 }
3365
on_slow_mode_delay_timeout_callback(void * contacts_manager_ptr,int64 channel_id_long)3366 void ContactsManager::on_slow_mode_delay_timeout_callback(void *contacts_manager_ptr, int64 channel_id_long) {
3367 if (G()->close_flag()) {
3368 return;
3369 }
3370
3371 auto contacts_manager = static_cast<ContactsManager *>(contacts_manager_ptr);
3372 send_closure_later(contacts_manager->actor_id(contacts_manager), &ContactsManager::on_slow_mode_delay_timeout,
3373 ChannelId(channel_id_long));
3374 }
3375
on_slow_mode_delay_timeout(ChannelId channel_id)3376 void ContactsManager::on_slow_mode_delay_timeout(ChannelId channel_id) {
3377 if (G()->close_flag()) {
3378 return;
3379 }
3380
3381 on_update_channel_slow_mode_next_send_date(channel_id, 0);
3382 }
3383
on_invite_link_info_expire_timeout_callback(void * contacts_manager_ptr,int64 dialog_id_long)3384 void ContactsManager::on_invite_link_info_expire_timeout_callback(void *contacts_manager_ptr, int64 dialog_id_long) {
3385 if (G()->close_flag()) {
3386 return;
3387 }
3388
3389 auto contacts_manager = static_cast<ContactsManager *>(contacts_manager_ptr);
3390 send_closure_later(contacts_manager->actor_id(contacts_manager), &ContactsManager::on_invite_link_info_expire_timeout,
3391 DialogId(dialog_id_long));
3392 }
3393
on_invite_link_info_expire_timeout(DialogId dialog_id)3394 void ContactsManager::on_invite_link_info_expire_timeout(DialogId dialog_id) {
3395 if (G()->close_flag()) {
3396 return;
3397 }
3398
3399 auto access_it = dialog_access_by_invite_link_.find(dialog_id);
3400 if (access_it == dialog_access_by_invite_link_.end()) {
3401 return;
3402 }
3403 auto expires_in = access_it->second.accessible_before - G()->unix_time() - 1;
3404 if (expires_in >= 3) {
3405 invite_link_info_expire_timeout_.set_timeout_in(dialog_id.get(), expires_in);
3406 return;
3407 }
3408
3409 remove_dialog_access_by_invite_link(dialog_id);
3410 }
3411
on_channel_participant_cache_timeout_callback(void * contacts_manager_ptr,int64 channel_id_long)3412 void ContactsManager::on_channel_participant_cache_timeout_callback(void *contacts_manager_ptr, int64 channel_id_long) {
3413 if (G()->close_flag()) {
3414 return;
3415 }
3416
3417 auto contacts_manager = static_cast<ContactsManager *>(contacts_manager_ptr);
3418 send_closure_later(contacts_manager->actor_id(contacts_manager),
3419 &ContactsManager::on_channel_participant_cache_timeout, ChannelId(channel_id_long));
3420 }
3421
on_channel_participant_cache_timeout(ChannelId channel_id)3422 void ContactsManager::on_channel_participant_cache_timeout(ChannelId channel_id) {
3423 if (G()->close_flag()) {
3424 return;
3425 }
3426
3427 auto channel_participants_it = channel_participants_.find(channel_id);
3428 if (channel_participants_it == channel_participants_.end()) {
3429 return;
3430 }
3431
3432 auto &participants = channel_participants_it->second.participants_;
3433 auto min_access_date = G()->unix_time() - CHANNEL_PARTICIPANT_CACHE_TIME;
3434 for (auto it = participants.begin(); it != participants.end();) {
3435 if (it->second.last_access_date_ < min_access_date) {
3436 it = participants.erase(it);
3437 } else {
3438 ++it;
3439 }
3440 }
3441
3442 if (participants.empty()) {
3443 channel_participants_.erase(channel_participants_it);
3444 } else {
3445 channel_participant_cache_timeout_.set_timeout_in(channel_id.get(), CHANNEL_PARTICIPANT_CACHE_TIME);
3446 }
3447 }
3448
3449 template <class StorerT>
store(StorerT & storer) const3450 void ContactsManager::User::store(StorerT &storer) const {
3451 using td::store;
3452 bool has_last_name = !last_name.empty();
3453 bool has_username = !username.empty();
3454 bool has_photo = photo.small_file_id.is_valid();
3455 bool has_language_code = !language_code.empty();
3456 bool have_access_hash = access_hash != -1;
3457 bool has_cache_version = cache_version != 0;
3458 bool has_is_contact = true;
3459 bool has_restriction_reasons = !restriction_reasons.empty();
3460 BEGIN_STORE_FLAGS();
3461 STORE_FLAG(is_received);
3462 STORE_FLAG(is_verified);
3463 STORE_FLAG(is_deleted);
3464 STORE_FLAG(is_bot);
3465 STORE_FLAG(can_join_groups);
3466 STORE_FLAG(can_read_all_group_messages);
3467 STORE_FLAG(is_inline_bot);
3468 STORE_FLAG(need_location_bot);
3469 STORE_FLAG(has_last_name);
3470 STORE_FLAG(has_username);
3471 STORE_FLAG(has_photo);
3472 STORE_FLAG(false); // legacy is_restricted
3473 STORE_FLAG(has_language_code);
3474 STORE_FLAG(have_access_hash);
3475 STORE_FLAG(is_support);
3476 STORE_FLAG(is_min_access_hash);
3477 STORE_FLAG(is_scam);
3478 STORE_FLAG(has_cache_version);
3479 STORE_FLAG(has_is_contact);
3480 STORE_FLAG(is_contact);
3481 STORE_FLAG(is_mutual_contact);
3482 STORE_FLAG(has_restriction_reasons);
3483 STORE_FLAG(need_apply_min_photo);
3484 STORE_FLAG(is_fake);
3485 END_STORE_FLAGS();
3486 store(first_name, storer);
3487 if (has_last_name) {
3488 store(last_name, storer);
3489 }
3490 if (has_username) {
3491 store(username, storer);
3492 }
3493 store(phone_number, storer);
3494 if (have_access_hash) {
3495 store(access_hash, storer);
3496 }
3497 if (has_photo) {
3498 store(photo, storer);
3499 }
3500 store(was_online, storer);
3501 if (has_restriction_reasons) {
3502 store(restriction_reasons, storer);
3503 }
3504 if (is_inline_bot) {
3505 store(inline_query_placeholder, storer);
3506 }
3507 if (is_bot) {
3508 store(bot_info_version, storer);
3509 }
3510 if (has_language_code) {
3511 store(language_code, storer);
3512 }
3513 if (has_cache_version) {
3514 store(cache_version, storer);
3515 }
3516 }
3517
3518 template <class ParserT>
parse(ParserT & parser)3519 void ContactsManager::User::parse(ParserT &parser) {
3520 using td::parse;
3521 bool has_last_name;
3522 bool has_username;
3523 bool has_photo;
3524 bool legacy_is_restricted;
3525 bool has_language_code;
3526 bool have_access_hash;
3527 bool has_cache_version;
3528 bool has_is_contact;
3529 bool has_restriction_reasons;
3530 BEGIN_PARSE_FLAGS();
3531 PARSE_FLAG(is_received);
3532 PARSE_FLAG(is_verified);
3533 PARSE_FLAG(is_deleted);
3534 PARSE_FLAG(is_bot);
3535 PARSE_FLAG(can_join_groups);
3536 PARSE_FLAG(can_read_all_group_messages);
3537 PARSE_FLAG(is_inline_bot);
3538 PARSE_FLAG(need_location_bot);
3539 PARSE_FLAG(has_last_name);
3540 PARSE_FLAG(has_username);
3541 PARSE_FLAG(has_photo);
3542 PARSE_FLAG(legacy_is_restricted);
3543 PARSE_FLAG(has_language_code);
3544 PARSE_FLAG(have_access_hash);
3545 PARSE_FLAG(is_support);
3546 PARSE_FLAG(is_min_access_hash);
3547 PARSE_FLAG(is_scam);
3548 PARSE_FLAG(has_cache_version);
3549 PARSE_FLAG(has_is_contact);
3550 PARSE_FLAG(is_contact);
3551 PARSE_FLAG(is_mutual_contact);
3552 PARSE_FLAG(has_restriction_reasons);
3553 PARSE_FLAG(need_apply_min_photo);
3554 PARSE_FLAG(is_fake);
3555 END_PARSE_FLAGS();
3556 parse(first_name, parser);
3557 if (has_last_name) {
3558 parse(last_name, parser);
3559 }
3560 if (has_username) {
3561 parse(username, parser);
3562 }
3563 parse(phone_number, parser);
3564 if (parser.version() < static_cast<int32>(Version::FixMinUsers)) {
3565 have_access_hash = is_received;
3566 }
3567 if (have_access_hash) {
3568 parse(access_hash, parser);
3569 } else {
3570 is_min_access_hash = true;
3571 }
3572 if (has_photo) {
3573 parse(photo, parser);
3574 }
3575 if (!has_is_contact) {
3576 // enum class LinkState : uint8 { Unknown, None, KnowsPhoneNumber, Contact };
3577
3578 uint32 link_state_inbound;
3579 uint32 link_state_outbound;
3580 parse(link_state_inbound, parser);
3581 parse(link_state_outbound, parser);
3582
3583 is_contact = link_state_outbound == 3;
3584 is_mutual_contact = is_contact && link_state_inbound == 3;
3585 }
3586 parse(was_online, parser);
3587 if (legacy_is_restricted) {
3588 string restriction_reason;
3589 parse(restriction_reason, parser);
3590 restriction_reasons = get_restriction_reasons(restriction_reason);
3591 } else if (has_restriction_reasons) {
3592 parse(restriction_reasons, parser);
3593 }
3594 if (is_inline_bot) {
3595 parse(inline_query_placeholder, parser);
3596 }
3597 if (is_bot) {
3598 parse(bot_info_version, parser);
3599 }
3600 if (has_language_code) {
3601 parse(language_code, parser);
3602 }
3603 if (has_cache_version) {
3604 parse(cache_version, parser);
3605 }
3606
3607 if (!check_utf8(first_name)) {
3608 LOG(ERROR) << "Have invalid first name \"" << first_name << '"';
3609 first_name.clear();
3610 cache_version = 0;
3611 }
3612 if (!check_utf8(last_name)) {
3613 LOG(ERROR) << "Have invalid last name \"" << last_name << '"';
3614 last_name.clear();
3615 cache_version = 0;
3616 }
3617 if (!check_utf8(username)) {
3618 LOG(ERROR) << "Have invalid username \"" << username << '"';
3619 username.clear();
3620 cache_version = 0;
3621 }
3622
3623 if (first_name.empty() && last_name.empty()) {
3624 first_name = phone_number;
3625 }
3626 if (!is_contact && is_mutual_contact) {
3627 LOG(ERROR) << "Have invalid flag is_mutual_contact";
3628 is_mutual_contact = false;
3629 cache_version = 0;
3630 }
3631 }
3632
3633 template <class StorerT>
store(StorerT & storer) const3634 void ContactsManager::UserFull::store(StorerT &storer) const {
3635 using td::store;
3636 bool has_about = !about.empty();
3637 bool has_photo = !photo.is_empty();
3638 bool has_description = !description.empty();
3639 bool has_commands = !commands.empty();
3640 bool has_private_forward_name = !private_forward_name.empty();
3641 BEGIN_STORE_FLAGS();
3642 STORE_FLAG(has_about);
3643 STORE_FLAG(is_blocked);
3644 STORE_FLAG(can_be_called);
3645 STORE_FLAG(has_private_calls);
3646 STORE_FLAG(can_pin_messages);
3647 STORE_FLAG(need_phone_number_privacy_exception);
3648 STORE_FLAG(has_photo);
3649 STORE_FLAG(supports_video_calls);
3650 STORE_FLAG(has_description);
3651 STORE_FLAG(has_commands);
3652 STORE_FLAG(has_private_forward_name);
3653 END_STORE_FLAGS();
3654 if (has_about) {
3655 store(about, storer);
3656 }
3657 store(common_chat_count, storer);
3658 store_time(expires_at, storer);
3659 if (has_photo) {
3660 store(photo, storer);
3661 }
3662 if (has_description) {
3663 store(description, storer);
3664 }
3665 if (has_commands) {
3666 store(commands, storer);
3667 }
3668 if (has_private_forward_name) {
3669 store(private_forward_name, storer);
3670 }
3671 }
3672
3673 template <class ParserT>
parse(ParserT & parser)3674 void ContactsManager::UserFull::parse(ParserT &parser) {
3675 using td::parse;
3676 bool has_about;
3677 bool has_photo;
3678 bool has_description;
3679 bool has_commands;
3680 bool has_private_forward_name;
3681 BEGIN_PARSE_FLAGS();
3682 PARSE_FLAG(has_about);
3683 PARSE_FLAG(is_blocked);
3684 PARSE_FLAG(can_be_called);
3685 PARSE_FLAG(has_private_calls);
3686 PARSE_FLAG(can_pin_messages);
3687 PARSE_FLAG(need_phone_number_privacy_exception);
3688 PARSE_FLAG(has_photo);
3689 PARSE_FLAG(supports_video_calls);
3690 PARSE_FLAG(has_description);
3691 PARSE_FLAG(has_commands);
3692 PARSE_FLAG(has_private_forward_name);
3693 END_PARSE_FLAGS();
3694 if (has_about) {
3695 parse(about, parser);
3696 }
3697 parse(common_chat_count, parser);
3698 parse_time(expires_at, parser);
3699 if (has_photo) {
3700 parse(photo, parser);
3701 }
3702 if (has_description) {
3703 parse(description, parser);
3704 }
3705 if (has_commands) {
3706 parse(commands, parser);
3707 }
3708 if (has_private_forward_name) {
3709 parse(private_forward_name, parser);
3710 }
3711 }
3712
3713 template <class StorerT>
store(StorerT & storer) const3714 void ContactsManager::Chat::store(StorerT &storer) const {
3715 using td::store;
3716 bool has_photo = photo.small_file_id.is_valid();
3717 bool use_new_rights = true;
3718 bool has_default_permissions_version = default_permissions_version != -1;
3719 bool has_pinned_message_version = pinned_message_version != -1;
3720 bool has_cache_version = cache_version != 0;
3721 BEGIN_STORE_FLAGS();
3722 STORE_FLAG(false);
3723 STORE_FLAG(false);
3724 STORE_FLAG(false);
3725 STORE_FLAG(false);
3726 STORE_FLAG(false);
3727 STORE_FLAG(false);
3728 STORE_FLAG(is_active);
3729 STORE_FLAG(has_photo);
3730 STORE_FLAG(use_new_rights);
3731 STORE_FLAG(has_default_permissions_version);
3732 STORE_FLAG(has_pinned_message_version);
3733 STORE_FLAG(has_cache_version);
3734 STORE_FLAG(noforwards);
3735 END_STORE_FLAGS();
3736
3737 store(title, storer);
3738 if (has_photo) {
3739 store(photo, storer);
3740 }
3741 store(participant_count, storer);
3742 store(date, storer);
3743 store(migrated_to_channel_id, storer);
3744 store(version, storer);
3745 store(status, storer);
3746 store(default_permissions, storer);
3747 if (has_default_permissions_version) {
3748 store(default_permissions_version, storer);
3749 }
3750 if (has_pinned_message_version) {
3751 store(pinned_message_version, storer);
3752 }
3753 if (has_cache_version) {
3754 store(cache_version, storer);
3755 }
3756 }
3757
3758 template <class ParserT>
parse(ParserT & parser)3759 void ContactsManager::Chat::parse(ParserT &parser) {
3760 using td::parse;
3761 bool has_photo;
3762 bool left;
3763 bool kicked;
3764 bool is_creator;
3765 bool is_administrator;
3766 bool everyone_is_administrator;
3767 bool can_edit;
3768 bool use_new_rights;
3769 bool has_default_permissions_version;
3770 bool has_pinned_message_version;
3771 bool has_cache_version;
3772 BEGIN_PARSE_FLAGS();
3773 PARSE_FLAG(left);
3774 PARSE_FLAG(kicked);
3775 PARSE_FLAG(is_creator);
3776 PARSE_FLAG(is_administrator);
3777 PARSE_FLAG(everyone_is_administrator);
3778 PARSE_FLAG(can_edit);
3779 PARSE_FLAG(is_active);
3780 PARSE_FLAG(has_photo);
3781 PARSE_FLAG(use_new_rights);
3782 PARSE_FLAG(has_default_permissions_version);
3783 PARSE_FLAG(has_pinned_message_version);
3784 PARSE_FLAG(has_cache_version);
3785 PARSE_FLAG(noforwards);
3786 END_PARSE_FLAGS();
3787
3788 parse(title, parser);
3789 if (has_photo) {
3790 parse(photo, parser);
3791 }
3792 parse(participant_count, parser);
3793 parse(date, parser);
3794 parse(migrated_to_channel_id, parser);
3795 parse(version, parser);
3796 if (use_new_rights) {
3797 parse(status, parser);
3798 parse(default_permissions, parser);
3799 } else {
3800 if (can_edit != (is_creator || is_administrator || everyone_is_administrator)) {
3801 LOG(ERROR) << "Have wrong can_edit flag";
3802 }
3803
3804 if (kicked || !is_active) {
3805 status = DialogParticipantStatus::Banned(0);
3806 } else if (left) {
3807 status = DialogParticipantStatus::Left();
3808 } else if (is_creator) {
3809 status = DialogParticipantStatus::Creator(true, false, string());
3810 } else if (is_administrator && !everyone_is_administrator) {
3811 status = DialogParticipantStatus::GroupAdministrator(false);
3812 } else {
3813 status = DialogParticipantStatus::Member();
3814 }
3815 default_permissions = RestrictedRights(true, true, true, true, true, true, true, true, everyone_is_administrator,
3816 everyone_is_administrator, everyone_is_administrator);
3817 }
3818 if (has_default_permissions_version) {
3819 parse(default_permissions_version, parser);
3820 }
3821 if (has_pinned_message_version) {
3822 parse(pinned_message_version, parser);
3823 }
3824 if (has_cache_version) {
3825 parse(cache_version, parser);
3826 }
3827
3828 if (!check_utf8(title)) {
3829 LOG(ERROR) << "Have invalid title \"" << title << '"';
3830 title.clear();
3831 cache_version = 0;
3832 }
3833
3834 if (status.is_administrator() && !status.is_creator()) {
3835 status = DialogParticipantStatus::GroupAdministrator(false);
3836 }
3837 }
3838
3839 template <class StorerT>
store(StorerT & storer) const3840 void ContactsManager::ChatFull::store(StorerT &storer) const {
3841 using td::store;
3842 bool has_description = !description.empty();
3843 bool has_legacy_invite_link = false;
3844 bool has_photo = !photo.is_empty();
3845 bool has_invite_link = invite_link.is_valid();
3846 bool has_bot_commands = !bot_commands.empty();
3847 BEGIN_STORE_FLAGS();
3848 STORE_FLAG(has_description);
3849 STORE_FLAG(has_legacy_invite_link);
3850 STORE_FLAG(can_set_username);
3851 STORE_FLAG(has_photo);
3852 STORE_FLAG(has_invite_link);
3853 STORE_FLAG(has_bot_commands);
3854 END_STORE_FLAGS();
3855 store(version, storer);
3856 store(creator_user_id, storer);
3857 store(participants, storer);
3858 if (has_description) {
3859 store(description, storer);
3860 }
3861 if (has_photo) {
3862 store(photo, storer);
3863 }
3864 if (has_invite_link) {
3865 store(invite_link, storer);
3866 }
3867 if (has_bot_commands) {
3868 store(bot_commands, storer);
3869 }
3870 }
3871
3872 template <class ParserT>
parse(ParserT & parser)3873 void ContactsManager::ChatFull::parse(ParserT &parser) {
3874 using td::parse;
3875 bool has_description;
3876 bool legacy_has_invite_link;
3877 bool has_photo;
3878 bool has_invite_link;
3879 bool has_bot_commands;
3880 BEGIN_PARSE_FLAGS();
3881 PARSE_FLAG(has_description);
3882 PARSE_FLAG(legacy_has_invite_link);
3883 PARSE_FLAG(can_set_username);
3884 PARSE_FLAG(has_photo);
3885 PARSE_FLAG(has_invite_link);
3886 PARSE_FLAG(has_bot_commands);
3887 END_PARSE_FLAGS();
3888 parse(version, parser);
3889 parse(creator_user_id, parser);
3890 parse(participants, parser);
3891 if (has_description) {
3892 parse(description, parser);
3893 }
3894 if (legacy_has_invite_link) {
3895 string legacy_invite_link;
3896 parse(legacy_invite_link, parser);
3897 }
3898 if (has_photo) {
3899 parse(photo, parser);
3900 }
3901 if (has_invite_link) {
3902 parse(invite_link, parser);
3903 }
3904 if (has_bot_commands) {
3905 parse(bot_commands, parser);
3906 }
3907 }
3908
3909 template <class StorerT>
store(StorerT & storer) const3910 void ContactsManager::Channel::store(StorerT &storer) const {
3911 using td::store;
3912 bool has_photo = photo.small_file_id.is_valid();
3913 bool has_username = !username.empty();
3914 bool use_new_rights = true;
3915 bool has_participant_count = participant_count != 0;
3916 bool have_default_permissions = true;
3917 bool has_cache_version = cache_version != 0;
3918 bool has_restriction_reasons = !restriction_reasons.empty();
3919 bool legacy_has_active_group_call = false;
3920 BEGIN_STORE_FLAGS();
3921 STORE_FLAG(false);
3922 STORE_FLAG(false);
3923 STORE_FLAG(false);
3924 STORE_FLAG(sign_messages);
3925 STORE_FLAG(false);
3926 STORE_FLAG(false); // 5
3927 STORE_FLAG(false);
3928 STORE_FLAG(is_megagroup);
3929 STORE_FLAG(is_verified);
3930 STORE_FLAG(has_photo);
3931 STORE_FLAG(has_username); // 10
3932 STORE_FLAG(false);
3933 STORE_FLAG(use_new_rights);
3934 STORE_FLAG(has_participant_count);
3935 STORE_FLAG(have_default_permissions);
3936 STORE_FLAG(is_scam); // 15
3937 STORE_FLAG(has_cache_version);
3938 STORE_FLAG(has_linked_channel);
3939 STORE_FLAG(has_location);
3940 STORE_FLAG(is_slow_mode_enabled);
3941 STORE_FLAG(has_restriction_reasons); // 20
3942 STORE_FLAG(legacy_has_active_group_call);
3943 STORE_FLAG(is_fake);
3944 STORE_FLAG(is_gigagroup);
3945 STORE_FLAG(noforwards);
3946 END_STORE_FLAGS();
3947
3948 store(status, storer);
3949 store(access_hash, storer);
3950 store(title, storer);
3951 if (has_photo) {
3952 store(photo, storer);
3953 }
3954 if (has_username) {
3955 store(username, storer);
3956 }
3957 store(date, storer);
3958 if (has_restriction_reasons) {
3959 store(restriction_reasons, storer);
3960 }
3961 if (has_participant_count) {
3962 store(participant_count, storer);
3963 }
3964 if (is_megagroup) {
3965 store(default_permissions, storer);
3966 }
3967 if (has_cache_version) {
3968 store(cache_version, storer);
3969 }
3970 }
3971
3972 template <class ParserT>
parse(ParserT & parser)3973 void ContactsManager::Channel::parse(ParserT &parser) {
3974 using td::parse;
3975 bool has_photo;
3976 bool has_username;
3977 bool legacy_is_restricted;
3978 bool left;
3979 bool kicked;
3980 bool is_creator;
3981 bool can_edit;
3982 bool can_moderate;
3983 bool anyone_can_invite;
3984 bool use_new_rights;
3985 bool has_participant_count;
3986 bool have_default_permissions;
3987 bool has_cache_version;
3988 bool has_restriction_reasons;
3989 bool legacy_has_active_group_call;
3990 BEGIN_PARSE_FLAGS();
3991 PARSE_FLAG(left);
3992 PARSE_FLAG(kicked);
3993 PARSE_FLAG(anyone_can_invite);
3994 PARSE_FLAG(sign_messages);
3995 PARSE_FLAG(is_creator);
3996 PARSE_FLAG(can_edit);
3997 PARSE_FLAG(can_moderate);
3998 PARSE_FLAG(is_megagroup);
3999 PARSE_FLAG(is_verified);
4000 PARSE_FLAG(has_photo);
4001 PARSE_FLAG(has_username);
4002 PARSE_FLAG(legacy_is_restricted);
4003 PARSE_FLAG(use_new_rights);
4004 PARSE_FLAG(has_participant_count);
4005 PARSE_FLAG(have_default_permissions);
4006 PARSE_FLAG(is_scam);
4007 PARSE_FLAG(has_cache_version);
4008 PARSE_FLAG(has_linked_channel);
4009 PARSE_FLAG(has_location);
4010 PARSE_FLAG(is_slow_mode_enabled);
4011 PARSE_FLAG(has_restriction_reasons);
4012 PARSE_FLAG(legacy_has_active_group_call);
4013 PARSE_FLAG(is_fake);
4014 PARSE_FLAG(is_gigagroup);
4015 PARSE_FLAG(noforwards);
4016 END_PARSE_FLAGS();
4017
4018 if (use_new_rights) {
4019 parse(status, parser);
4020 } else {
4021 if (kicked) {
4022 status = DialogParticipantStatus::Banned(0);
4023 } else if (left) {
4024 status = DialogParticipantStatus::Left();
4025 } else if (is_creator) {
4026 status = DialogParticipantStatus::Creator(true, false, string());
4027 } else if (can_edit || can_moderate) {
4028 status = DialogParticipantStatus::ChannelAdministrator(false, is_megagroup);
4029 } else {
4030 status = DialogParticipantStatus::Member();
4031 }
4032 }
4033 parse(access_hash, parser);
4034 parse(title, parser);
4035 if (has_photo) {
4036 parse(photo, parser);
4037 }
4038 if (has_username) {
4039 parse(username, parser);
4040 }
4041 parse(date, parser);
4042 if (legacy_is_restricted) {
4043 string restriction_reason;
4044 parse(restriction_reason, parser);
4045 restriction_reasons = get_restriction_reasons(restriction_reason);
4046 } else if (has_restriction_reasons) {
4047 parse(restriction_reasons, parser);
4048 }
4049 if (has_participant_count) {
4050 parse(participant_count, parser);
4051 }
4052 if (is_megagroup) {
4053 if (have_default_permissions) {
4054 parse(default_permissions, parser);
4055 } else {
4056 default_permissions =
4057 RestrictedRights(true, true, true, true, true, true, true, true, false, anyone_can_invite, false);
4058 }
4059 }
4060 if (has_cache_version) {
4061 parse(cache_version, parser);
4062 }
4063
4064 if (!check_utf8(title)) {
4065 LOG(ERROR) << "Have invalid title \"" << title << '"';
4066 title.clear();
4067 cache_version = 0;
4068 }
4069 if (!check_utf8(username)) {
4070 LOG(ERROR) << "Have invalid username \"" << username << '"';
4071 username.clear();
4072 cache_version = 0;
4073 }
4074 if (legacy_has_active_group_call) {
4075 cache_version = 0;
4076 }
4077 }
4078
4079 template <class StorerT>
store(StorerT & storer) const4080 void ContactsManager::ChannelFull::store(StorerT &storer) const {
4081 using td::store;
4082 bool has_description = !description.empty();
4083 bool has_administrator_count = administrator_count != 0;
4084 bool has_restricted_count = restricted_count != 0;
4085 bool has_banned_count = banned_count != 0;
4086 bool legacy_has_invite_link = false;
4087 bool has_sticker_set = sticker_set_id.is_valid();
4088 bool has_linked_channel_id = linked_channel_id.is_valid();
4089 bool has_migrated_from_max_message_id = migrated_from_max_message_id.is_valid();
4090 bool has_migrated_from_chat_id = migrated_from_chat_id.is_valid();
4091 bool has_location = !location.empty();
4092 bool has_bot_user_ids = !bot_user_ids.empty();
4093 bool is_slow_mode_enabled = slow_mode_delay != 0;
4094 bool is_slow_mode_delay_active = slow_mode_next_send_date != 0;
4095 bool has_stats_dc_id = stats_dc_id.is_exact();
4096 bool has_photo = !photo.is_empty();
4097 bool legacy_has_active_group_call_id = false;
4098 bool has_invite_link = invite_link.is_valid();
4099 bool has_bot_commands = !bot_commands.empty();
4100 BEGIN_STORE_FLAGS();
4101 STORE_FLAG(has_description);
4102 STORE_FLAG(has_administrator_count);
4103 STORE_FLAG(has_restricted_count);
4104 STORE_FLAG(has_banned_count);
4105 STORE_FLAG(legacy_has_invite_link);
4106 STORE_FLAG(has_sticker_set);
4107 STORE_FLAG(has_linked_channel_id);
4108 STORE_FLAG(has_migrated_from_max_message_id);
4109 STORE_FLAG(has_migrated_from_chat_id);
4110 STORE_FLAG(can_get_participants);
4111 STORE_FLAG(can_set_username);
4112 STORE_FLAG(can_set_sticker_set);
4113 STORE_FLAG(false); // legacy_can_view_statistics
4114 STORE_FLAG(is_all_history_available);
4115 STORE_FLAG(can_set_location);
4116 STORE_FLAG(has_location);
4117 STORE_FLAG(has_bot_user_ids);
4118 STORE_FLAG(is_slow_mode_enabled);
4119 STORE_FLAG(is_slow_mode_delay_active);
4120 STORE_FLAG(has_stats_dc_id);
4121 STORE_FLAG(has_photo);
4122 STORE_FLAG(is_can_view_statistics_inited);
4123 STORE_FLAG(can_view_statistics);
4124 STORE_FLAG(legacy_has_active_group_call_id);
4125 STORE_FLAG(has_invite_link);
4126 STORE_FLAG(has_bot_commands);
4127 END_STORE_FLAGS();
4128 if (has_description) {
4129 store(description, storer);
4130 }
4131 store(participant_count, storer);
4132 if (has_administrator_count) {
4133 store(administrator_count, storer);
4134 }
4135 if (has_restricted_count) {
4136 store(restricted_count, storer);
4137 }
4138 if (has_banned_count) {
4139 store(banned_count, storer);
4140 }
4141 if (has_sticker_set) {
4142 store(sticker_set_id, storer);
4143 }
4144 if (has_linked_channel_id) {
4145 store(linked_channel_id, storer);
4146 }
4147 if (has_location) {
4148 store(location, storer);
4149 }
4150 if (has_bot_user_ids) {
4151 store(bot_user_ids, storer);
4152 }
4153 if (has_migrated_from_max_message_id) {
4154 store(migrated_from_max_message_id, storer);
4155 }
4156 if (has_migrated_from_chat_id) {
4157 store(migrated_from_chat_id, storer);
4158 }
4159 if (is_slow_mode_enabled) {
4160 store(slow_mode_delay, storer);
4161 }
4162 if (is_slow_mode_delay_active) {
4163 store(slow_mode_next_send_date, storer);
4164 }
4165 store_time(expires_at, storer);
4166 if (has_stats_dc_id) {
4167 store(stats_dc_id.get_raw_id(), storer);
4168 }
4169 if (has_photo) {
4170 store(photo, storer);
4171 }
4172 if (has_invite_link) {
4173 store(invite_link, storer);
4174 }
4175 if (has_bot_commands) {
4176 store(bot_commands, storer);
4177 }
4178 }
4179
4180 template <class ParserT>
parse(ParserT & parser)4181 void ContactsManager::ChannelFull::parse(ParserT &parser) {
4182 using td::parse;
4183 bool has_description;
4184 bool has_administrator_count;
4185 bool has_restricted_count;
4186 bool has_banned_count;
4187 bool legacy_has_invite_link;
4188 bool has_sticker_set;
4189 bool has_linked_channel_id;
4190 bool has_migrated_from_max_message_id;
4191 bool has_migrated_from_chat_id;
4192 bool legacy_can_view_statistics;
4193 bool has_location;
4194 bool has_bot_user_ids;
4195 bool is_slow_mode_enabled;
4196 bool is_slow_mode_delay_active;
4197 bool has_stats_dc_id;
4198 bool has_photo;
4199 bool legacy_has_active_group_call_id;
4200 bool has_invite_link;
4201 bool has_bot_commands;
4202 BEGIN_PARSE_FLAGS();
4203 PARSE_FLAG(has_description);
4204 PARSE_FLAG(has_administrator_count);
4205 PARSE_FLAG(has_restricted_count);
4206 PARSE_FLAG(has_banned_count);
4207 PARSE_FLAG(legacy_has_invite_link);
4208 PARSE_FLAG(has_sticker_set);
4209 PARSE_FLAG(has_linked_channel_id);
4210 PARSE_FLAG(has_migrated_from_max_message_id);
4211 PARSE_FLAG(has_migrated_from_chat_id);
4212 PARSE_FLAG(can_get_participants);
4213 PARSE_FLAG(can_set_username);
4214 PARSE_FLAG(can_set_sticker_set);
4215 PARSE_FLAG(legacy_can_view_statistics);
4216 PARSE_FLAG(is_all_history_available);
4217 PARSE_FLAG(can_set_location);
4218 PARSE_FLAG(has_location);
4219 PARSE_FLAG(has_bot_user_ids);
4220 PARSE_FLAG(is_slow_mode_enabled);
4221 PARSE_FLAG(is_slow_mode_delay_active);
4222 PARSE_FLAG(has_stats_dc_id);
4223 PARSE_FLAG(has_photo);
4224 PARSE_FLAG(is_can_view_statistics_inited);
4225 PARSE_FLAG(can_view_statistics);
4226 PARSE_FLAG(legacy_has_active_group_call_id);
4227 PARSE_FLAG(has_invite_link);
4228 PARSE_FLAG(has_bot_commands);
4229 END_PARSE_FLAGS();
4230 if (has_description) {
4231 parse(description, parser);
4232 }
4233 parse(participant_count, parser);
4234 if (has_administrator_count) {
4235 parse(administrator_count, parser);
4236 }
4237 if (has_restricted_count) {
4238 parse(restricted_count, parser);
4239 }
4240 if (has_banned_count) {
4241 parse(banned_count, parser);
4242 }
4243 if (legacy_has_invite_link) {
4244 string legacy_invite_link;
4245 parse(legacy_invite_link, parser);
4246 }
4247 if (has_sticker_set) {
4248 parse(sticker_set_id, parser);
4249 }
4250 if (has_linked_channel_id) {
4251 parse(linked_channel_id, parser);
4252 }
4253 if (has_location) {
4254 parse(location, parser);
4255 }
4256 if (has_bot_user_ids) {
4257 parse(bot_user_ids, parser);
4258 }
4259 if (has_migrated_from_max_message_id) {
4260 parse(migrated_from_max_message_id, parser);
4261 }
4262 if (has_migrated_from_chat_id) {
4263 parse(migrated_from_chat_id, parser);
4264 }
4265 if (is_slow_mode_enabled) {
4266 parse(slow_mode_delay, parser);
4267 }
4268 if (is_slow_mode_delay_active) {
4269 parse(slow_mode_next_send_date, parser);
4270 }
4271 parse_time(expires_at, parser);
4272 if (has_stats_dc_id) {
4273 stats_dc_id = DcId::create(parser.fetch_int());
4274 }
4275 if (has_photo) {
4276 parse(photo, parser);
4277 }
4278 if (legacy_has_active_group_call_id) {
4279 InputGroupCallId input_group_call_id;
4280 parse(input_group_call_id, parser);
4281 }
4282 if (has_invite_link) {
4283 parse(invite_link, parser);
4284 }
4285 if (has_bot_commands) {
4286 parse(bot_commands, parser);
4287 }
4288
4289 if (legacy_can_view_statistics) {
4290 LOG(DEBUG) << "Ignore legacy can view statistics flag";
4291 }
4292 if (!is_can_view_statistics_inited) {
4293 can_view_statistics = stats_dc_id.is_exact();
4294 }
4295 }
4296
4297 template <class StorerT>
store(StorerT & storer) const4298 void ContactsManager::SecretChat::store(StorerT &storer) const {
4299 using td::store;
4300 bool has_layer = layer > static_cast<int32>(SecretChatLayer::Default);
4301 bool has_initial_folder_id = initial_folder_id != FolderId();
4302 BEGIN_STORE_FLAGS();
4303 STORE_FLAG(is_outbound);
4304 STORE_FLAG(has_layer);
4305 STORE_FLAG(has_initial_folder_id);
4306 END_STORE_FLAGS();
4307
4308 store(access_hash, storer);
4309 store(user_id, storer);
4310 store(state, storer);
4311 store(ttl, storer);
4312 store(date, storer);
4313 store(key_hash, storer);
4314 if (has_layer) {
4315 store(layer, storer);
4316 }
4317 if (has_initial_folder_id) {
4318 store(initial_folder_id, storer);
4319 }
4320 }
4321
4322 template <class ParserT>
parse(ParserT & parser)4323 void ContactsManager::SecretChat::parse(ParserT &parser) {
4324 using td::parse;
4325 bool has_layer;
4326 bool has_initial_folder_id;
4327 BEGIN_PARSE_FLAGS();
4328 PARSE_FLAG(is_outbound);
4329 PARSE_FLAG(has_layer);
4330 PARSE_FLAG(has_initial_folder_id);
4331 END_PARSE_FLAGS();
4332
4333 if (parser.version() >= static_cast<int32>(Version::AddAccessHashToSecretChat)) {
4334 parse(access_hash, parser);
4335 }
4336 parse(user_id, parser);
4337 parse(state, parser);
4338 parse(ttl, parser);
4339 parse(date, parser);
4340 if (parser.version() >= static_cast<int32>(Version::AddKeyHashToSecretChat)) {
4341 parse(key_hash, parser);
4342 }
4343 if (has_layer) {
4344 parse(layer, parser);
4345 } else {
4346 layer = static_cast<int32>(SecretChatLayer::Default);
4347 }
4348 if (has_initial_folder_id) {
4349 parse(initial_folder_id, parser);
4350 }
4351 }
4352
get_input_user(UserId user_id) const4353 tl_object_ptr<telegram_api::InputUser> ContactsManager::get_input_user(UserId user_id) const {
4354 if (user_id == get_my_id()) {
4355 return make_tl_object<telegram_api::inputUserSelf>();
4356 }
4357
4358 const User *u = get_user(user_id);
4359 if (u == nullptr || u->access_hash == -1 || u->is_min_access_hash) {
4360 if (td_->auth_manager_->is_bot() && user_id.is_valid()) {
4361 return make_tl_object<telegram_api::inputUser>(user_id.get(), 0);
4362 }
4363 return nullptr;
4364 }
4365
4366 return make_tl_object<telegram_api::inputUser>(user_id.get(), u->access_hash);
4367 }
4368
have_input_user(UserId user_id) const4369 bool ContactsManager::have_input_user(UserId user_id) const {
4370 if (user_id == get_my_id()) {
4371 return true;
4372 }
4373
4374 const User *u = get_user(user_id);
4375 if (u == nullptr || u->access_hash == -1 || u->is_min_access_hash) {
4376 if (td_->auth_manager_->is_bot() && user_id.is_valid()) {
4377 return true;
4378 }
4379 return false;
4380 }
4381
4382 return true;
4383 }
4384
get_input_channel(ChannelId channel_id) const4385 tl_object_ptr<telegram_api::InputChannel> ContactsManager::get_input_channel(ChannelId channel_id) const {
4386 const Channel *c = get_channel(channel_id);
4387 if (c == nullptr) {
4388 if (td_->auth_manager_->is_bot() && channel_id.is_valid()) {
4389 return make_tl_object<telegram_api::inputChannel>(channel_id.get(), 0);
4390 }
4391 return nullptr;
4392 }
4393
4394 return make_tl_object<telegram_api::inputChannel>(channel_id.get(), c->access_hash);
4395 }
4396
have_input_peer_user(UserId user_id,AccessRights access_rights) const4397 bool ContactsManager::have_input_peer_user(UserId user_id, AccessRights access_rights) const {
4398 if (user_id == get_my_id()) {
4399 return true;
4400 }
4401 return have_input_peer_user(get_user(user_id), access_rights);
4402 }
4403
have_input_peer_user(const User * u,AccessRights access_rights)4404 bool ContactsManager::have_input_peer_user(const User *u, AccessRights access_rights) {
4405 if (u == nullptr) {
4406 return false;
4407 }
4408 if (u->access_hash == -1 || u->is_min_access_hash) {
4409 return false;
4410 }
4411 if (access_rights == AccessRights::Know) {
4412 return true;
4413 }
4414 if (access_rights == AccessRights::Read) {
4415 return true;
4416 }
4417 if (u->is_deleted) {
4418 return false;
4419 }
4420 return true;
4421 }
4422
get_input_peer_user(UserId user_id,AccessRights access_rights) const4423 tl_object_ptr<telegram_api::InputPeer> ContactsManager::get_input_peer_user(UserId user_id,
4424 AccessRights access_rights) const {
4425 if (user_id == get_my_id()) {
4426 return make_tl_object<telegram_api::inputPeerSelf>();
4427 }
4428 const User *u = get_user(user_id);
4429 if (!have_input_peer_user(u, access_rights)) {
4430 if ((u == nullptr || u->access_hash == -1 || u->is_min_access_hash) && td_->auth_manager_->is_bot() &&
4431 user_id.is_valid()) {
4432 return make_tl_object<telegram_api::inputPeerUser>(user_id.get(), 0);
4433 }
4434 return nullptr;
4435 }
4436
4437 return make_tl_object<telegram_api::inputPeerUser>(user_id.get(), u->access_hash);
4438 }
4439
have_input_peer_chat(ChatId chat_id,AccessRights access_rights) const4440 bool ContactsManager::have_input_peer_chat(ChatId chat_id, AccessRights access_rights) const {
4441 return have_input_peer_chat(get_chat(chat_id), access_rights);
4442 }
4443
have_input_peer_chat(const Chat * c,AccessRights access_rights)4444 bool ContactsManager::have_input_peer_chat(const Chat *c, AccessRights access_rights) {
4445 if (c == nullptr) {
4446 return false;
4447 }
4448 if (access_rights == AccessRights::Know) {
4449 return true;
4450 }
4451 if (access_rights == AccessRights::Read) {
4452 return true;
4453 }
4454 if (c->status.is_left()) {
4455 return false;
4456 }
4457 if (access_rights == AccessRights::Write && !c->is_active) {
4458 return false;
4459 }
4460 return true;
4461 }
4462
get_input_peer_chat(ChatId chat_id,AccessRights access_rights) const4463 tl_object_ptr<telegram_api::InputPeer> ContactsManager::get_input_peer_chat(ChatId chat_id,
4464 AccessRights access_rights) const {
4465 auto c = get_chat(chat_id);
4466 if (!have_input_peer_chat(c, access_rights)) {
4467 return nullptr;
4468 }
4469
4470 return make_tl_object<telegram_api::inputPeerChat>(chat_id.get());
4471 }
4472
have_input_peer_channel(ChannelId channel_id,AccessRights access_rights) const4473 bool ContactsManager::have_input_peer_channel(ChannelId channel_id, AccessRights access_rights) const {
4474 const Channel *c = get_channel(channel_id);
4475 return have_input_peer_channel(c, channel_id, access_rights);
4476 }
4477
get_input_peer_channel(ChannelId channel_id,AccessRights access_rights) const4478 tl_object_ptr<telegram_api::InputPeer> ContactsManager::get_input_peer_channel(ChannelId channel_id,
4479 AccessRights access_rights) const {
4480 const Channel *c = get_channel(channel_id);
4481 if (!have_input_peer_channel(c, channel_id, access_rights)) {
4482 if (c == nullptr && td_->auth_manager_->is_bot() && channel_id.is_valid()) {
4483 return make_tl_object<telegram_api::inputPeerChannel>(channel_id.get(), 0);
4484 }
4485 return nullptr;
4486 }
4487
4488 return make_tl_object<telegram_api::inputPeerChannel>(channel_id.get(), c->access_hash);
4489 }
4490
have_input_peer_channel(const Channel * c,ChannelId channel_id,AccessRights access_rights,bool from_linked) const4491 bool ContactsManager::have_input_peer_channel(const Channel *c, ChannelId channel_id, AccessRights access_rights,
4492 bool from_linked) const {
4493 if (c == nullptr) {
4494 return false;
4495 }
4496 if (access_rights == AccessRights::Know) {
4497 return true;
4498 }
4499 if (c->status.is_administrator()) {
4500 return true;
4501 }
4502 if (c->status.is_banned()) {
4503 return false;
4504 }
4505 if (c->status.is_member()) {
4506 return true;
4507 }
4508
4509 bool is_public = is_channel_public(c);
4510 if (access_rights == AccessRights::Read) {
4511 if (is_public) {
4512 return true;
4513 }
4514 if (!from_linked && c->has_linked_channel) {
4515 auto linked_channel_id = get_linked_channel_id(channel_id);
4516 if (linked_channel_id.is_valid() && have_channel(linked_channel_id)) {
4517 if (have_input_peer_channel(get_channel(linked_channel_id), linked_channel_id, access_rights, true)) {
4518 return true;
4519 }
4520 } else {
4521 return true;
4522 }
4523 }
4524 if (!from_linked && dialog_access_by_invite_link_.count(DialogId(channel_id))) {
4525 return true;
4526 }
4527 } else {
4528 if (!from_linked && c->is_megagroup && !td_->auth_manager_->is_bot() && c->has_linked_channel) {
4529 auto linked_channel_id = get_linked_channel_id(channel_id);
4530 if (linked_channel_id.is_valid() && (is_public || have_channel(linked_channel_id))) {
4531 return is_public ||
4532 have_input_peer_channel(get_channel(linked_channel_id), linked_channel_id, AccessRights::Read, true);
4533 } else {
4534 return true;
4535 }
4536 }
4537 }
4538 return false;
4539 }
4540
have_input_encrypted_peer(SecretChatId secret_chat_id,AccessRights access_rights) const4541 bool ContactsManager::have_input_encrypted_peer(SecretChatId secret_chat_id, AccessRights access_rights) const {
4542 return have_input_encrypted_peer(get_secret_chat(secret_chat_id), access_rights);
4543 }
4544
have_input_encrypted_peer(const SecretChat * secret_chat,AccessRights access_rights)4545 bool ContactsManager::have_input_encrypted_peer(const SecretChat *secret_chat, AccessRights access_rights) {
4546 if (secret_chat == nullptr) {
4547 return false;
4548 }
4549 if (access_rights == AccessRights::Know) {
4550 return true;
4551 }
4552 if (access_rights == AccessRights::Read) {
4553 return true;
4554 }
4555 return secret_chat->state == SecretChatState::Active;
4556 }
4557
get_input_encrypted_chat(SecretChatId secret_chat_id,AccessRights access_rights) const4558 tl_object_ptr<telegram_api::inputEncryptedChat> ContactsManager::get_input_encrypted_chat(
4559 SecretChatId secret_chat_id, AccessRights access_rights) const {
4560 auto sc = get_secret_chat(secret_chat_id);
4561 if (!have_input_encrypted_peer(sc, access_rights)) {
4562 return nullptr;
4563 }
4564
4565 return make_tl_object<telegram_api::inputEncryptedChat>(secret_chat_id.get(), sc->access_hash);
4566 }
4567
get_user_dialog_photo(UserId user_id)4568 const DialogPhoto *ContactsManager::get_user_dialog_photo(UserId user_id) {
4569 auto u = get_user(user_id);
4570 if (u == nullptr) {
4571 return nullptr;
4572 }
4573
4574 if (!u->is_photo_inited) {
4575 auto it = pending_user_photos_.find(user_id);
4576 if (it != pending_user_photos_.end()) {
4577 do_update_user_photo(u, user_id, std::move(it->second), "get_user_dialog_photo");
4578 pending_user_photos_.erase(it);
4579 update_user(u, user_id);
4580 }
4581 }
4582 return &u->photo;
4583 }
4584
get_chat_dialog_photo(ChatId chat_id) const4585 const DialogPhoto *ContactsManager::get_chat_dialog_photo(ChatId chat_id) const {
4586 auto c = get_chat(chat_id);
4587 if (c == nullptr) {
4588 return nullptr;
4589 }
4590 return &c->photo;
4591 }
4592
get_channel_dialog_photo(ChannelId channel_id) const4593 const DialogPhoto *ContactsManager::get_channel_dialog_photo(ChannelId channel_id) const {
4594 auto c = get_channel(channel_id);
4595 if (c == nullptr) {
4596 return nullptr;
4597 }
4598 return &c->photo;
4599 }
4600
get_secret_chat_dialog_photo(SecretChatId secret_chat_id)4601 const DialogPhoto *ContactsManager::get_secret_chat_dialog_photo(SecretChatId secret_chat_id) {
4602 auto c = get_secret_chat(secret_chat_id);
4603 if (c == nullptr) {
4604 return nullptr;
4605 }
4606 return get_user_dialog_photo(c->user_id);
4607 }
4608
get_user_title(UserId user_id) const4609 string ContactsManager::get_user_title(UserId user_id) const {
4610 auto u = get_user(user_id);
4611 if (u == nullptr) {
4612 return string();
4613 }
4614 if (u->last_name.empty()) {
4615 return u->first_name;
4616 }
4617 if (u->first_name.empty()) {
4618 return u->last_name;
4619 }
4620 return PSTRING() << u->first_name << ' ' << u->last_name;
4621 }
4622
get_chat_title(ChatId chat_id) const4623 string ContactsManager::get_chat_title(ChatId chat_id) const {
4624 auto c = get_chat(chat_id);
4625 if (c == nullptr) {
4626 return string();
4627 }
4628 return c->title;
4629 }
4630
get_channel_title(ChannelId channel_id) const4631 string ContactsManager::get_channel_title(ChannelId channel_id) const {
4632 auto c = get_channel(channel_id);
4633 if (c == nullptr) {
4634 return string();
4635 }
4636 return c->title;
4637 }
4638
get_secret_chat_title(SecretChatId secret_chat_id) const4639 string ContactsManager::get_secret_chat_title(SecretChatId secret_chat_id) const {
4640 auto c = get_secret_chat(secret_chat_id);
4641 if (c == nullptr) {
4642 return string();
4643 }
4644 return get_user_title(c->user_id);
4645 }
4646
get_user_default_permissions(UserId user_id) const4647 RestrictedRights ContactsManager::get_user_default_permissions(UserId user_id) const {
4648 auto u = get_user(user_id);
4649 if (u == nullptr || user_id == get_replies_bot_user_id()) {
4650 return RestrictedRights(false, false, false, false, false, false, false, false, false, false, u != nullptr);
4651 }
4652 return RestrictedRights(true, true, true, true, true, true, true, true, false, false, true);
4653 }
4654
get_chat_default_permissions(ChatId chat_id) const4655 RestrictedRights ContactsManager::get_chat_default_permissions(ChatId chat_id) const {
4656 auto c = get_chat(chat_id);
4657 if (c == nullptr) {
4658 return RestrictedRights(false, false, false, false, false, false, false, false, false, false, false);
4659 }
4660 return c->default_permissions;
4661 }
4662
get_channel_default_permissions(ChannelId channel_id) const4663 RestrictedRights ContactsManager::get_channel_default_permissions(ChannelId channel_id) const {
4664 auto c = get_channel(channel_id);
4665 if (c == nullptr) {
4666 return RestrictedRights(false, false, false, false, false, false, false, false, false, false, false);
4667 }
4668 return c->default_permissions;
4669 }
4670
get_secret_chat_default_permissions(SecretChatId secret_chat_id) const4671 RestrictedRights ContactsManager::get_secret_chat_default_permissions(SecretChatId secret_chat_id) const {
4672 auto c = get_secret_chat(secret_chat_id);
4673 if (c == nullptr) {
4674 return RestrictedRights(false, false, false, false, false, false, false, false, false, false, false);
4675 }
4676 return RestrictedRights(true, true, true, true, true, true, true, true, false, false, false);
4677 }
4678
get_chat_has_protected_content(ChatId chat_id) const4679 bool ContactsManager::get_chat_has_protected_content(ChatId chat_id) const {
4680 auto c = get_chat(chat_id);
4681 if (c == nullptr) {
4682 return false;
4683 }
4684 return c->noforwards;
4685 }
4686
get_channel_has_protected_content(ChannelId channel_id) const4687 bool ContactsManager::get_channel_has_protected_content(ChannelId channel_id) const {
4688 auto c = get_channel(channel_id);
4689 if (c == nullptr) {
4690 return false;
4691 }
4692 return c->noforwards;
4693 }
4694
get_user_private_forward_name(UserId user_id)4695 string ContactsManager::get_user_private_forward_name(UserId user_id) {
4696 auto user_full = get_user_full_force(user_id);
4697 if (user_full != nullptr) {
4698 return user_full->private_forward_name;
4699 }
4700 return string();
4701 }
4702
get_dialog_about(DialogId dialog_id)4703 string ContactsManager::get_dialog_about(DialogId dialog_id) {
4704 switch (dialog_id.get_type()) {
4705 case DialogType::User: {
4706 auto user_full = get_user_full_force(dialog_id.get_user_id());
4707 if (user_full != nullptr) {
4708 return user_full->about;
4709 }
4710 break;
4711 }
4712 case DialogType::Chat: {
4713 auto chat_full = get_chat_full_force(dialog_id.get_chat_id(), "get_dialog_about");
4714 if (chat_full != nullptr) {
4715 return chat_full->description;
4716 }
4717 break;
4718 }
4719 case DialogType::Channel: {
4720 auto channel_full = get_channel_full_force(dialog_id.get_channel_id(), false, "get_dialog_about");
4721 if (channel_full != nullptr) {
4722 return channel_full->description;
4723 }
4724 break;
4725 }
4726 case DialogType::SecretChat: {
4727 auto user_full = get_user_full_force(get_secret_chat_user_id(dialog_id.get_secret_chat_id()));
4728 if (user_full != nullptr) {
4729 return user_full->about;
4730 }
4731 break;
4732 }
4733 case DialogType::None:
4734 default:
4735 UNREACHABLE();
4736 }
4737 return string();
4738 }
4739
get_secret_chat_date(SecretChatId secret_chat_id) const4740 int32 ContactsManager::get_secret_chat_date(SecretChatId secret_chat_id) const {
4741 auto c = get_secret_chat(secret_chat_id);
4742 if (c == nullptr) {
4743 return 0;
4744 }
4745 return c->date;
4746 }
4747
get_secret_chat_ttl(SecretChatId secret_chat_id) const4748 int32 ContactsManager::get_secret_chat_ttl(SecretChatId secret_chat_id) const {
4749 auto c = get_secret_chat(secret_chat_id);
4750 if (c == nullptr) {
4751 return 0;
4752 }
4753 return c->ttl;
4754 }
4755
get_user_username(UserId user_id) const4756 string ContactsManager::get_user_username(UserId user_id) const {
4757 if (!user_id.is_valid()) {
4758 return string();
4759 }
4760
4761 auto u = get_user(user_id);
4762 if (u == nullptr) {
4763 return string();
4764 }
4765 return u->username;
4766 }
4767
get_secret_chat_username(SecretChatId secret_chat_id) const4768 string ContactsManager::get_secret_chat_username(SecretChatId secret_chat_id) const {
4769 auto c = get_secret_chat(secret_chat_id);
4770 if (c == nullptr) {
4771 return string();
4772 }
4773 return get_user_username(c->user_id);
4774 }
4775
get_channel_username(ChannelId channel_id) const4776 string ContactsManager::get_channel_username(ChannelId channel_id) const {
4777 auto c = get_channel(channel_id);
4778 if (c == nullptr) {
4779 return string();
4780 }
4781 return c->username;
4782 }
4783
get_secret_chat_user_id(SecretChatId secret_chat_id) const4784 UserId ContactsManager::get_secret_chat_user_id(SecretChatId secret_chat_id) const {
4785 auto c = get_secret_chat(secret_chat_id);
4786 if (c == nullptr) {
4787 return UserId();
4788 }
4789 return c->user_id;
4790 }
4791
get_secret_chat_is_outbound(SecretChatId secret_chat_id) const4792 bool ContactsManager::get_secret_chat_is_outbound(SecretChatId secret_chat_id) const {
4793 auto c = get_secret_chat(secret_chat_id);
4794 if (c == nullptr) {
4795 return false;
4796 }
4797 return c->is_outbound;
4798 }
4799
get_secret_chat_state(SecretChatId secret_chat_id) const4800 SecretChatState ContactsManager::get_secret_chat_state(SecretChatId secret_chat_id) const {
4801 auto c = get_secret_chat(secret_chat_id);
4802 if (c == nullptr) {
4803 return SecretChatState::Unknown;
4804 }
4805 return c->state;
4806 }
4807
get_secret_chat_layer(SecretChatId secret_chat_id) const4808 int32 ContactsManager::get_secret_chat_layer(SecretChatId secret_chat_id) const {
4809 auto c = get_secret_chat(secret_chat_id);
4810 if (c == nullptr) {
4811 return 0;
4812 }
4813 return c->layer;
4814 }
4815
get_secret_chat_initial_folder_id(SecretChatId secret_chat_id) const4816 FolderId ContactsManager::get_secret_chat_initial_folder_id(SecretChatId secret_chat_id) const {
4817 auto c = get_secret_chat(secret_chat_id);
4818 if (c == nullptr) {
4819 return FolderId::main();
4820 }
4821 return c->initial_folder_id;
4822 }
4823
get_my_id() const4824 UserId ContactsManager::get_my_id() const {
4825 LOG_IF(ERROR, !my_id_.is_valid()) << "Wrong or unknown my ID returned";
4826 return my_id_;
4827 }
4828
set_my_id(UserId my_id)4829 void ContactsManager::set_my_id(UserId my_id) {
4830 UserId my_old_id = my_id_;
4831 if (my_old_id.is_valid() && my_old_id != my_id) {
4832 LOG(ERROR) << "Already know that me is " << my_old_id << " but received userSelf with " << my_id;
4833 }
4834 if (!my_id.is_valid()) {
4835 LOG(ERROR) << "Receive invalid my ID " << my_id;
4836 return;
4837 }
4838 if (my_old_id != my_id) {
4839 my_id_ = my_id;
4840 G()->td_db()->get_binlog_pmc()->set("my_id", to_string(my_id.get()));
4841 G()->shared_config().set_option_integer("my_id", my_id_.get());
4842 G()->td_db()->get_binlog_pmc()->force_sync(Promise<Unit>());
4843 }
4844 }
4845
set_my_online_status(bool is_online,bool send_update,bool is_local)4846 void ContactsManager::set_my_online_status(bool is_online, bool send_update, bool is_local) {
4847 if (td_->auth_manager_->is_bot()) {
4848 return; // just in case
4849 }
4850
4851 auto my_id = get_my_id();
4852 User *u = get_user_force(my_id);
4853 if (u != nullptr) {
4854 int32 new_online;
4855 int32 now = G()->unix_time();
4856 if (is_online) {
4857 new_online = now + 300;
4858 } else {
4859 new_online = now - 1;
4860 }
4861
4862 if (is_local) {
4863 LOG(INFO) << "Update my local online from " << my_was_online_local_ << " to " << new_online;
4864 if (!is_online) {
4865 new_online = min(new_online, u->was_online);
4866 }
4867 if (new_online != my_was_online_local_) {
4868 my_was_online_local_ = new_online;
4869 u->is_status_changed = true;
4870 u->is_online_status_changed = true;
4871 }
4872 } else {
4873 if (my_was_online_local_ != 0 || new_online != u->was_online) {
4874 LOG(INFO) << "Update my online from " << u->was_online << " to " << new_online;
4875 my_was_online_local_ = 0;
4876 u->was_online = new_online;
4877 u->is_status_changed = true;
4878 u->is_online_status_changed = true;
4879 }
4880 }
4881
4882 if (was_online_local_ != new_online) {
4883 was_online_local_ = new_online;
4884 VLOG(notifications) << "Set was_online_local to " << was_online_local_;
4885 G()->td_db()->get_binlog_pmc()->set("my_was_online_local", to_string(was_online_local_));
4886 }
4887
4888 if (send_update) {
4889 update_user(u, my_id);
4890 }
4891 }
4892 }
4893
get_my_online_status() const4894 ContactsManager::MyOnlineStatusInfo ContactsManager::get_my_online_status() const {
4895 MyOnlineStatusInfo status_info;
4896 status_info.is_online_local = td_->is_online();
4897 status_info.is_online_remote = was_online_remote_ > G()->unix_time_cached();
4898 status_info.was_online_local = was_online_local_;
4899 status_info.was_online_remote = was_online_remote_;
4900
4901 return status_info;
4902 }
4903
get_service_notifications_user_id()4904 UserId ContactsManager::get_service_notifications_user_id() {
4905 return UserId(static_cast<int64>(777000));
4906 }
4907
add_service_notifications_user()4908 UserId ContactsManager::add_service_notifications_user() {
4909 auto user_id = get_service_notifications_user_id();
4910 if (!have_user_force(user_id)) {
4911 LOG(FATAL) << "Failed to load service notification user";
4912 }
4913 return user_id;
4914 }
4915
get_replies_bot_user_id()4916 UserId ContactsManager::get_replies_bot_user_id() {
4917 return UserId(static_cast<int64>(G()->is_test_dc() ? 708513 : 1271266957));
4918 }
4919
get_anonymous_bot_user_id()4920 UserId ContactsManager::get_anonymous_bot_user_id() {
4921 return UserId(static_cast<int64>(G()->is_test_dc() ? 552888 : 1087968824));
4922 }
4923
add_anonymous_bot_user()4924 UserId ContactsManager::add_anonymous_bot_user() {
4925 auto user_id = get_anonymous_bot_user_id();
4926 if (!have_user_force(user_id)) {
4927 LOG(FATAL) << "Failed to load anonymous bot user";
4928 }
4929 return user_id;
4930 }
4931
check_dialog_username(DialogId dialog_id,const string & username,Promise<CheckDialogUsernameResult> && promise)4932 void ContactsManager::check_dialog_username(DialogId dialog_id, const string &username,
4933 Promise<CheckDialogUsernameResult> &&promise) {
4934 if (dialog_id != DialogId() && !dialog_id.is_valid()) {
4935 return promise.set_error(Status::Error(400, "Chat not found"));
4936 }
4937
4938 switch (dialog_id.get_type()) {
4939 case DialogType::User: {
4940 if (dialog_id.get_user_id() != get_my_id()) {
4941 return promise.set_error(Status::Error(400, "Can't check username for private chat with other user"));
4942 }
4943 break;
4944 }
4945 case DialogType::Channel: {
4946 auto c = get_channel(dialog_id.get_channel_id());
4947 if (c == nullptr) {
4948 return promise.set_error(Status::Error(400, "Chat not found"));
4949 }
4950 if (!get_channel_status(c).is_creator()) {
4951 return promise.set_error(Status::Error(400, "Not enough rights to change username"));
4952 }
4953
4954 if (username == c->username) {
4955 return promise.set_value(CheckDialogUsernameResult::Ok);
4956 }
4957 break;
4958 }
4959 case DialogType::None:
4960 break;
4961 case DialogType::Chat:
4962 case DialogType::SecretChat:
4963 if (username.empty()) {
4964 return promise.set_value(CheckDialogUsernameResult::Ok);
4965 }
4966 return promise.set_error(Status::Error(400, "Chat can't have username"));
4967 default:
4968 UNREACHABLE();
4969 return;
4970 }
4971
4972 if (username.empty()) {
4973 return promise.set_value(CheckDialogUsernameResult::Ok);
4974 }
4975 if (!is_valid_username(username)) {
4976 return promise.set_value(CheckDialogUsernameResult::Invalid);
4977 }
4978
4979 auto request_promise = PromiseCreator::lambda([promise = std::move(promise)](Result<bool> result) mutable {
4980 if (result.is_error()) {
4981 auto error = result.move_as_error();
4982 if (error.message() == "CHANNEL_PUBLIC_GROUP_NA") {
4983 return promise.set_value(CheckDialogUsernameResult::PublicGroupsUnavailable);
4984 }
4985 if (error.message() == "CHANNELS_ADMIN_PUBLIC_TOO_MUCH") {
4986 return promise.set_value(CheckDialogUsernameResult::PublicDialogsTooMuch);
4987 }
4988 if (error.message() == "USERNAME_INVALID") {
4989 return promise.set_value(CheckDialogUsernameResult::Invalid);
4990 }
4991 return promise.set_error(std::move(error));
4992 }
4993
4994 promise.set_value(result.ok() ? CheckDialogUsernameResult::Ok : CheckDialogUsernameResult::Occupied);
4995 });
4996
4997 switch (dialog_id.get_type()) {
4998 case DialogType::User:
4999 return td_->create_handler<CheckUsernameQuery>(std::move(request_promise))->send(username);
5000 case DialogType::Channel:
5001 return td_->create_handler<CheckChannelUsernameQuery>(std::move(request_promise))
5002 ->send(dialog_id.get_channel_id(), username);
5003 case DialogType::None:
5004 return td_->create_handler<CheckChannelUsernameQuery>(std::move(request_promise))->send(ChannelId(), username);
5005 case DialogType::Chat:
5006 case DialogType::SecretChat:
5007 default:
5008 UNREACHABLE();
5009 }
5010 }
5011
get_check_chat_username_result_object(CheckDialogUsernameResult result)5012 td_api::object_ptr<td_api::CheckChatUsernameResult> ContactsManager::get_check_chat_username_result_object(
5013 CheckDialogUsernameResult result) {
5014 switch (result) {
5015 case CheckDialogUsernameResult::Ok:
5016 return td_api::make_object<td_api::checkChatUsernameResultOk>();
5017 case CheckDialogUsernameResult::Invalid:
5018 return td_api::make_object<td_api::checkChatUsernameResultUsernameInvalid>();
5019 case CheckDialogUsernameResult::Occupied:
5020 return td_api::make_object<td_api::checkChatUsernameResultUsernameOccupied>();
5021 case CheckDialogUsernameResult::PublicDialogsTooMuch:
5022 return td_api::make_object<td_api::checkChatUsernameResultPublicChatsTooMuch>();
5023 case CheckDialogUsernameResult::PublicGroupsUnavailable:
5024 return td_api::make_object<td_api::checkChatUsernameResultPublicGroupsUnavailable>();
5025 default:
5026 UNREACHABLE();
5027 return nullptr;
5028 }
5029 }
5030
is_valid_username(const string & username)5031 bool ContactsManager::is_valid_username(const string &username) {
5032 if (username.size() < 5 || username.size() > 32) {
5033 return false;
5034 }
5035 if (!is_alpha(username[0])) {
5036 return false;
5037 }
5038 for (auto c : username) {
5039 if (!is_alpha(c) && !is_digit(c) && c != '_') {
5040 return false;
5041 }
5042 }
5043 if (username.back() == '_') {
5044 return false;
5045 }
5046 for (size_t i = 1; i < username.size(); i++) {
5047 if (username[i - 1] == '_' && username[i] == '_') {
5048 return false;
5049 }
5050 }
5051 if (username.find("admin") == 0 || username.find("telegram") == 0 || username.find("support") == 0 ||
5052 username.find("security") == 0 || username.find("settings") == 0 || username.find("contacts") == 0 ||
5053 username.find("service") == 0 || username.find("telegraph") == 0) {
5054 return false;
5055 }
5056 return true;
5057 }
5058
get_user_was_online(const User * u,UserId user_id) const5059 int32 ContactsManager::get_user_was_online(const User *u, UserId user_id) const {
5060 if (u == nullptr || u->is_deleted) {
5061 return 0;
5062 }
5063
5064 int32 was_online = u->was_online;
5065 if (user_id == get_my_id()) {
5066 if (my_was_online_local_ != 0) {
5067 was_online = my_was_online_local_;
5068 }
5069 } else {
5070 if (u->local_was_online > 0 && u->local_was_online > was_online && u->local_was_online > G()->unix_time_cached()) {
5071 was_online = u->local_was_online;
5072 }
5073 }
5074 return was_online;
5075 }
5076
load_contacts(Promise<Unit> && promise)5077 void ContactsManager::load_contacts(Promise<Unit> &&promise) {
5078 if (td_->auth_manager_->is_bot()) {
5079 are_contacts_loaded_ = true;
5080 saved_contact_count_ = 0;
5081 }
5082 if (are_contacts_loaded_ && saved_contact_count_ != -1) {
5083 LOG(INFO) << "Contacts are already loaded";
5084 promise.set_value(Unit());
5085 return;
5086 }
5087 load_contacts_queries_.push_back(std::move(promise));
5088 if (load_contacts_queries_.size() == 1u) {
5089 if (G()->parameters().use_chat_info_db && next_contacts_sync_date_ > 0 && saved_contact_count_ != -1) {
5090 LOG(INFO) << "Load contacts from database";
5091 G()->td_db()->get_sqlite_pmc()->get(
5092 "user_contacts", PromiseCreator::lambda([](string value) {
5093 send_closure(G()->contacts_manager(), &ContactsManager::on_load_contacts_from_database, std::move(value));
5094 }));
5095 } else {
5096 LOG(INFO) << "Load contacts from server";
5097 reload_contacts(true);
5098 }
5099 } else {
5100 LOG(INFO) << "Load contacts request has already been sent";
5101 }
5102 }
5103
get_contacts_hash()5104 int64 ContactsManager::get_contacts_hash() {
5105 if (!are_contacts_loaded_) {
5106 return 0;
5107 }
5108
5109 vector<int64> user_ids = contacts_hints_.search_empty(100000).second;
5110 CHECK(std::is_sorted(user_ids.begin(), user_ids.end()));
5111 auto my_id = get_my_id();
5112 const User *u = get_user_force(my_id);
5113 if (u != nullptr && u->is_contact) {
5114 user_ids.insert(std::upper_bound(user_ids.begin(), user_ids.end(), my_id.get()), my_id.get());
5115 }
5116
5117 vector<uint64> numbers;
5118 numbers.reserve(user_ids.size() + 1);
5119 numbers.push_back(saved_contact_count_);
5120 for (auto user_id : user_ids) {
5121 numbers.push_back(user_id);
5122 }
5123 return get_vector_hash(numbers);
5124 }
5125
reload_contacts(bool force)5126 void ContactsManager::reload_contacts(bool force) {
5127 if (!td_->auth_manager_->is_bot() && next_contacts_sync_date_ != std::numeric_limits<int32>::max() &&
5128 (next_contacts_sync_date_ < G()->unix_time() || force)) {
5129 next_contacts_sync_date_ = std::numeric_limits<int32>::max();
5130 td_->create_handler<GetContactsQuery>()->send(get_contacts_hash());
5131 }
5132 }
5133
add_contact(Contact contact,bool share_phone_number,Promise<Unit> && promise)5134 void ContactsManager::add_contact(Contact contact, bool share_phone_number, Promise<Unit> &&promise) {
5135 TRY_STATUS_PROMISE(promise, G()->close_status());
5136
5137 if (!are_contacts_loaded_) {
5138 load_contacts(PromiseCreator::lambda([actor_id = actor_id(this), contact = std::move(contact), share_phone_number,
5139 promise = std::move(promise)](Result<Unit> &&) mutable {
5140 send_closure(actor_id, &ContactsManager::add_contact, std::move(contact), share_phone_number, std::move(promise));
5141 }));
5142 return;
5143 }
5144
5145 LOG(INFO) << "Add " << contact << " with share_phone_number = " << share_phone_number;
5146
5147 auto user_id = contact.get_user_id();
5148 auto input_user = get_input_user(user_id);
5149 if (input_user == nullptr) {
5150 return promise.set_error(Status::Error(400, "User not found"));
5151 }
5152
5153 td_->create_handler<AddContactQuery>(std::move(promise))
5154 ->send(user_id, std::move(input_user), contact, share_phone_number);
5155 }
5156
import_contacts(const vector<Contact> & contacts,int64 & random_id,Promise<Unit> && promise)5157 std::pair<vector<UserId>, vector<int32>> ContactsManager::import_contacts(const vector<Contact> &contacts,
5158 int64 &random_id, Promise<Unit> &&promise) {
5159 if (!are_contacts_loaded_) {
5160 load_contacts(std::move(promise));
5161 return {};
5162 }
5163
5164 LOG(INFO) << "Asked to import " << contacts.size() << " contacts with random_id = " << random_id;
5165 if (random_id != 0) {
5166 // request has already been sent before
5167 auto it = imported_contacts_.find(random_id);
5168 CHECK(it != imported_contacts_.end());
5169 auto result = std::move(it->second);
5170 imported_contacts_.erase(it);
5171
5172 promise.set_value(Unit());
5173 return result;
5174 }
5175
5176 do {
5177 random_id = Random::secure_int64();
5178 } while (random_id == 0 || imported_contacts_.find(random_id) != imported_contacts_.end());
5179 imported_contacts_[random_id]; // reserve place for result
5180
5181 do_import_contacts(contacts, random_id, std::move(promise));
5182 return {};
5183 }
5184
do_import_contacts(vector<Contact> contacts,int64 random_id,Promise<Unit> && promise)5185 void ContactsManager::do_import_contacts(vector<Contact> contacts, int64 random_id, Promise<Unit> &&promise) {
5186 size_t size = contacts.size();
5187 if (size == 0) {
5188 on_import_contacts_finished(random_id, {}, {});
5189 return promise.set_value(Unit());
5190 }
5191
5192 vector<tl_object_ptr<telegram_api::inputPhoneContact>> input_phone_contacts;
5193 input_phone_contacts.reserve(size);
5194 for (size_t i = 0; i < size; i++) {
5195 input_phone_contacts.push_back(contacts[i].get_input_phone_contact(static_cast<int64>(i)));
5196 }
5197
5198 auto task = make_unique<ImportContactsTask>();
5199 task->promise_ = std::move(promise);
5200 task->input_contacts_ = std::move(contacts);
5201 task->imported_user_ids_.resize(size);
5202 task->unimported_contact_invites_.resize(size);
5203
5204 bool is_added = import_contact_tasks_.emplace(random_id, std::move(task)).second;
5205 CHECK(is_added);
5206
5207 td_->create_handler<ImportContactsQuery>()->send(std::move(input_phone_contacts), random_id);
5208 }
5209
on_imported_contacts(int64 random_id,Result<tl_object_ptr<telegram_api::contacts_importedContacts>> result)5210 void ContactsManager::on_imported_contacts(int64 random_id,
5211 Result<tl_object_ptr<telegram_api::contacts_importedContacts>> result) {
5212 auto it = import_contact_tasks_.find(random_id);
5213 CHECK(it != import_contact_tasks_.end());
5214 CHECK(it->second != nullptr);
5215
5216 auto task = it->second.get();
5217 if (result.is_error()) {
5218 auto promise = std::move(task->promise_);
5219 import_contact_tasks_.erase(it);
5220 return promise.set_error(result.move_as_error());
5221 }
5222
5223 auto imported_contacts = result.move_as_ok();
5224 on_get_users(std::move(imported_contacts->users_), "on_imported_contacts");
5225
5226 for (auto &imported_contact : imported_contacts->imported_) {
5227 int64 client_id = imported_contact->client_id_;
5228 if (client_id < 0 || client_id >= static_cast<int64>(task->imported_user_ids_.size())) {
5229 LOG(ERROR) << "Wrong client_id " << client_id << " returned";
5230 continue;
5231 }
5232
5233 task->imported_user_ids_[static_cast<size_t>(client_id)] = UserId(imported_contact->user_id_);
5234 }
5235 for (auto &popular_contact : imported_contacts->popular_invites_) {
5236 int64 client_id = popular_contact->client_id_;
5237 if (client_id < 0 || client_id >= static_cast<int64>(task->unimported_contact_invites_.size())) {
5238 LOG(ERROR) << "Wrong client_id " << client_id << " returned";
5239 continue;
5240 }
5241 if (popular_contact->importers_ < 0) {
5242 LOG(ERROR) << "Wrong number of importers " << popular_contact->importers_ << " returned";
5243 continue;
5244 }
5245
5246 task->unimported_contact_invites_[static_cast<size_t>(client_id)] = popular_contact->importers_;
5247 }
5248
5249 if (!imported_contacts->retry_contacts_.empty()) {
5250 auto total_size = static_cast<int64>(task->input_contacts_.size());
5251 vector<tl_object_ptr<telegram_api::inputPhoneContact>> input_phone_contacts;
5252 input_phone_contacts.reserve(imported_contacts->retry_contacts_.size());
5253 for (auto &client_id : imported_contacts->retry_contacts_) {
5254 if (client_id < 0 || client_id >= total_size) {
5255 LOG(ERROR) << "Wrong client_id " << client_id << " returned";
5256 continue;
5257 }
5258 auto i = static_cast<size_t>(client_id);
5259 input_phone_contacts.push_back(task->input_contacts_[i].get_input_phone_contact(client_id));
5260 }
5261 td_->create_handler<ImportContactsQuery>()->send(std::move(input_phone_contacts), random_id);
5262 return;
5263 }
5264
5265 auto promise = std::move(task->promise_);
5266 on_import_contacts_finished(random_id, std::move(task->imported_user_ids_),
5267 std::move(task->unimported_contact_invites_));
5268 import_contact_tasks_.erase(it);
5269 promise.set_value(Unit());
5270 }
5271
remove_contacts(const vector<UserId> & user_ids,Promise<Unit> && promise)5272 void ContactsManager::remove_contacts(const vector<UserId> &user_ids, Promise<Unit> &&promise) {
5273 LOG(INFO) << "Delete contacts: " << format::as_array(user_ids);
5274 if (!are_contacts_loaded_) {
5275 load_contacts(std::move(promise));
5276 return;
5277 }
5278
5279 vector<UserId> to_delete_user_ids;
5280 vector<tl_object_ptr<telegram_api::InputUser>> input_users;
5281 for (auto &user_id : user_ids) {
5282 const User *u = get_user(user_id);
5283 if (u != nullptr && u->is_contact) {
5284 auto input_user = get_input_user(user_id);
5285 if (input_user != nullptr) {
5286 to_delete_user_ids.push_back(user_id);
5287 input_users.push_back(std::move(input_user));
5288 }
5289 }
5290 }
5291
5292 if (input_users.empty()) {
5293 return promise.set_value(Unit());
5294 }
5295
5296 td_->create_handler<DeleteContactsQuery>(std::move(promise))->send(std::move(input_users));
5297 }
5298
remove_contacts_by_phone_number(vector<string> user_phone_numbers,vector<UserId> user_ids,Promise<Unit> && promise)5299 void ContactsManager::remove_contacts_by_phone_number(vector<string> user_phone_numbers, vector<UserId> user_ids,
5300 Promise<Unit> &&promise) {
5301 LOG(INFO) << "Delete contacts by phone number: " << format::as_array(user_phone_numbers);
5302 if (!are_contacts_loaded_) {
5303 load_contacts(std::move(promise));
5304 return;
5305 }
5306
5307 td_->create_handler<DeleteContactsByPhoneNumberQuery>(std::move(promise))
5308 ->send(std::move(user_phone_numbers), std::move(user_ids));
5309 }
5310
get_imported_contact_count(Promise<Unit> && promise)5311 int32 ContactsManager::get_imported_contact_count(Promise<Unit> &&promise) {
5312 LOG(INFO) << "Get imported contact count";
5313
5314 if (!are_contacts_loaded_ || saved_contact_count_ == -1) {
5315 load_contacts(std::move(promise));
5316 return 0;
5317 }
5318 reload_contacts(false);
5319
5320 promise.set_value(Unit());
5321 return saved_contact_count_;
5322 }
5323
load_imported_contacts(Promise<Unit> && promise)5324 void ContactsManager::load_imported_contacts(Promise<Unit> &&promise) {
5325 if (td_->auth_manager_->is_bot()) {
5326 are_imported_contacts_loaded_ = true;
5327 }
5328 if (are_imported_contacts_loaded_) {
5329 LOG(INFO) << "Imported contacts are already loaded";
5330 promise.set_value(Unit());
5331 return;
5332 }
5333 load_imported_contacts_queries_.push_back(std::move(promise));
5334 if (load_imported_contacts_queries_.size() == 1u) {
5335 if (G()->parameters().use_chat_info_db) {
5336 LOG(INFO) << "Load imported contacts from database";
5337 G()->td_db()->get_sqlite_pmc()->get(
5338 "user_imported_contacts", PromiseCreator::lambda([](string value) {
5339 send_closure_later(G()->contacts_manager(), &ContactsManager::on_load_imported_contacts_from_database,
5340 std::move(value));
5341 }));
5342 } else {
5343 LOG(INFO) << "Have no previously imported contacts";
5344 send_closure_later(G()->contacts_manager(), &ContactsManager::on_load_imported_contacts_from_database, string());
5345 }
5346 } else {
5347 LOG(INFO) << "Load imported contacts request has already been sent";
5348 }
5349 }
5350
on_load_imported_contacts_from_database(string value)5351 void ContactsManager::on_load_imported_contacts_from_database(string value) {
5352 if (G()->close_flag()) {
5353 return;
5354 }
5355
5356 CHECK(!are_imported_contacts_loaded_);
5357 if (need_clear_imported_contacts_) {
5358 need_clear_imported_contacts_ = false;
5359 value.clear();
5360 }
5361 if (value.empty()) {
5362 CHECK(all_imported_contacts_.empty());
5363 } else {
5364 log_event_parse(all_imported_contacts_, value).ensure();
5365 LOG(INFO) << "Successfully loaded " << all_imported_contacts_.size() << " imported contacts from database";
5366 }
5367
5368 load_imported_contact_users_multipromise_.add_promise(
5369 PromiseCreator::lambda([actor_id = actor_id(this)](Result<Unit> result) {
5370 if (result.is_ok()) {
5371 send_closure_later(actor_id, &ContactsManager::on_load_imported_contacts_finished);
5372 }
5373 }));
5374
5375 auto lock_promise = load_imported_contact_users_multipromise_.get_promise();
5376
5377 for (const auto &contact : all_imported_contacts_) {
5378 auto user_id = contact.get_user_id();
5379 if (user_id.is_valid()) {
5380 get_user(user_id, 3, load_imported_contact_users_multipromise_.get_promise());
5381 }
5382 }
5383
5384 lock_promise.set_value(Unit());
5385 }
5386
on_load_imported_contacts_finished()5387 void ContactsManager::on_load_imported_contacts_finished() {
5388 LOG(INFO) << "Finished to load " << all_imported_contacts_.size() << " imported contacts";
5389
5390 for (const auto &contact : all_imported_contacts_) {
5391 get_user_id_object(contact.get_user_id(), "on_load_imported_contacts_finished"); // to ensure updateUser
5392 }
5393
5394 if (need_clear_imported_contacts_) {
5395 need_clear_imported_contacts_ = false;
5396 all_imported_contacts_.clear();
5397 }
5398 are_imported_contacts_loaded_ = true;
5399 auto promises = std::move(load_imported_contacts_queries_);
5400 load_imported_contacts_queries_.clear();
5401 for (auto &promise : promises) {
5402 promise.set_value(Unit());
5403 }
5404 }
5405
change_imported_contacts(vector<Contact> & contacts,int64 & random_id,Promise<Unit> && promise)5406 std::pair<vector<UserId>, vector<int32>> ContactsManager::change_imported_contacts(vector<Contact> &contacts,
5407 int64 &random_id,
5408 Promise<Unit> &&promise) {
5409 if (!are_contacts_loaded_) {
5410 load_contacts(std::move(promise));
5411 return {};
5412 }
5413 if (!are_imported_contacts_loaded_) {
5414 load_imported_contacts(std::move(promise));
5415 return {};
5416 }
5417
5418 LOG(INFO) << "Asked to change imported contacts to a list of " << contacts.size()
5419 << " contacts with random_id = " << random_id;
5420 if (random_id != 0) {
5421 // request has already been sent before
5422 if (need_clear_imported_contacts_) {
5423 need_clear_imported_contacts_ = false;
5424 all_imported_contacts_.clear();
5425 if (G()->parameters().use_chat_info_db) {
5426 G()->td_db()->get_sqlite_pmc()->erase("user_imported_contacts", Auto());
5427 }
5428 reload_contacts(true);
5429 }
5430
5431 CHECK(are_imported_contacts_changing_);
5432 are_imported_contacts_changing_ = false;
5433
5434 auto unimported_contact_invites = std::move(unimported_contact_invites_);
5435 unimported_contact_invites_.clear();
5436
5437 auto imported_contact_user_ids = std::move(imported_contact_user_ids_);
5438 imported_contact_user_ids_.clear();
5439
5440 promise.set_value(Unit());
5441 return {std::move(imported_contact_user_ids), std::move(unimported_contact_invites)};
5442 }
5443
5444 if (are_imported_contacts_changing_) {
5445 promise.set_error(Status::Error(400, "ChangeImportedContacts can be called only once at the same time"));
5446 return {};
5447 }
5448
5449 vector<size_t> new_contacts_unique_id(contacts.size());
5450 vector<Contact> unique_new_contacts;
5451 unique_new_contacts.reserve(contacts.size());
5452 std::unordered_map<Contact, size_t, ContactHash, ContactEqual> different_new_contacts;
5453 std::unordered_set<string> different_new_phone_numbers;
5454 size_t unique_size = 0;
5455 for (size_t i = 0; i < contacts.size(); i++) {
5456 auto it_success = different_new_contacts.emplace(std::move(contacts[i]), unique_size);
5457 new_contacts_unique_id[i] = it_success.first->second;
5458 if (it_success.second) {
5459 unique_new_contacts.push_back(it_success.first->first);
5460 different_new_phone_numbers.insert(unique_new_contacts.back().get_phone_number());
5461 unique_size++;
5462 }
5463 }
5464
5465 vector<string> to_delete;
5466 vector<UserId> to_delete_user_ids;
5467 for (auto &old_contact : all_imported_contacts_) {
5468 auto user_id = old_contact.get_user_id();
5469 auto it = different_new_contacts.find(old_contact);
5470 if (it == different_new_contacts.end()) {
5471 auto phone_number = old_contact.get_phone_number();
5472 if (different_new_phone_numbers.count(phone_number) == 0) {
5473 to_delete.push_back(std::move(phone_number));
5474 if (user_id.is_valid()) {
5475 to_delete_user_ids.push_back(user_id);
5476 }
5477 }
5478 } else {
5479 unique_new_contacts[it->second].set_user_id(user_id);
5480 different_new_contacts.erase(it);
5481 }
5482 }
5483 std::pair<vector<size_t>, vector<Contact>> to_add;
5484 for (auto &new_contact : different_new_contacts) {
5485 to_add.first.push_back(new_contact.second);
5486 to_add.second.push_back(new_contact.first);
5487 }
5488
5489 if (to_add.first.empty() && to_delete.empty()) {
5490 for (size_t i = 0; i < contacts.size(); i++) {
5491 auto unique_id = new_contacts_unique_id[i];
5492 contacts[i].set_user_id(unique_new_contacts[unique_id].get_user_id());
5493 }
5494
5495 promise.set_value(Unit());
5496 return {transform(contacts, [&](const Contact &contact) { return contact.get_user_id(); }),
5497 vector<int32>(contacts.size())};
5498 }
5499
5500 are_imported_contacts_changing_ = true;
5501 random_id = 1;
5502
5503 remove_contacts_by_phone_number(
5504 std::move(to_delete), std::move(to_delete_user_ids),
5505 PromiseCreator::lambda([new_contacts = std::move(unique_new_contacts),
5506 new_contacts_unique_id = std::move(new_contacts_unique_id), to_add = std::move(to_add),
5507 promise = std::move(promise)](Result<> result) mutable {
5508 if (result.is_ok()) {
5509 send_closure_later(G()->contacts_manager(), &ContactsManager::on_clear_imported_contacts,
5510 std::move(new_contacts), std::move(new_contacts_unique_id), std::move(to_add),
5511 std::move(promise));
5512 } else {
5513 promise.set_error(result.move_as_error());
5514 }
5515 }));
5516 return {};
5517 }
5518
on_clear_imported_contacts(vector<Contact> && contacts,vector<size_t> contacts_unique_id,std::pair<vector<size_t>,vector<Contact>> && to_add,Promise<Unit> && promise)5519 void ContactsManager::on_clear_imported_contacts(vector<Contact> &&contacts, vector<size_t> contacts_unique_id,
5520 std::pair<vector<size_t>, vector<Contact>> &&to_add,
5521 Promise<Unit> &&promise) {
5522 LOG(INFO) << "Add " << to_add.first.size() << " contacts";
5523 next_all_imported_contacts_ = std::move(contacts);
5524 imported_contacts_unique_id_ = std::move(contacts_unique_id);
5525 imported_contacts_pos_ = std::move(to_add.first);
5526
5527 do_import_contacts(std::move(to_add.second), 0, std::move(promise));
5528 }
5529
clear_imported_contacts(Promise<Unit> && promise)5530 void ContactsManager::clear_imported_contacts(Promise<Unit> &&promise) {
5531 LOG(INFO) << "Delete imported contacts";
5532
5533 if (saved_contact_count_ == 0) {
5534 promise.set_value(Unit());
5535 return;
5536 }
5537
5538 td_->create_handler<ResetContactsQuery>(std::move(promise))->send();
5539 }
5540
on_update_contacts_reset()5541 void ContactsManager::on_update_contacts_reset() {
5542 /*
5543 UserId my_id = get_my_id();
5544 for (auto &p : users_) {
5545 UserId user_id = p.first;
5546 User u = &p.second;
5547 if (u->is_contact) {
5548 LOG(INFO) << "Drop contact with " << user_id;
5549 if (user_id != my_id) {
5550 CHECK(contacts_hints_.has_key(user_id.get()));
5551 }
5552 on_update_user_is_contact(u, user_id, false, false);
5553 CHECK(u->is_is_contact_changed);
5554 u->cache_version = 0;
5555 u->is_repaired = false;
5556 update_user(u, user_id);
5557 CHECK(!u->is_contact);
5558 if (user_id != my_id) {
5559 CHECK(!contacts_hints_.has_key(user_id.get()));
5560 }
5561 }
5562 }
5563 */
5564
5565 saved_contact_count_ = 0;
5566 if (G()->parameters().use_chat_info_db) {
5567 G()->td_db()->get_binlog_pmc()->set("saved_contact_count", "0");
5568 G()->td_db()->get_sqlite_pmc()->erase("user_imported_contacts", Auto());
5569 }
5570 if (!are_imported_contacts_loaded_) {
5571 CHECK(all_imported_contacts_.empty());
5572 if (load_imported_contacts_queries_.empty()) {
5573 LOG(INFO) << "Imported contacts was never loaded, just clear them";
5574 } else {
5575 LOG(INFO) << "Imported contacts are being loaded, clear them also when they will be loaded";
5576 need_clear_imported_contacts_ = true;
5577 }
5578 } else {
5579 if (!are_imported_contacts_changing_) {
5580 LOG(INFO) << "Imported contacts was loaded, but aren't changing now, just clear them";
5581 all_imported_contacts_.clear();
5582 } else {
5583 LOG(INFO) << "Imported contacts are changing now, clear them also after they will be loaded";
5584 need_clear_imported_contacts_ = true;
5585 }
5586 }
5587 reload_contacts(true);
5588 }
5589
search_contacts(const string & query,int32 limit,Promise<Unit> && promise)5590 std::pair<int32, vector<UserId>> ContactsManager::search_contacts(const string &query, int32 limit,
5591 Promise<Unit> &&promise) {
5592 LOG(INFO) << "Search contacts with query = \"" << query << "\" and limit = " << limit;
5593
5594 if (limit < 0) {
5595 promise.set_error(Status::Error(400, "Limit must be non-negative"));
5596 return {};
5597 }
5598
5599 if (!are_contacts_loaded_) {
5600 load_contacts(std::move(promise));
5601 return {};
5602 }
5603 reload_contacts(false);
5604
5605 std::pair<size_t, vector<int64>> result;
5606 if (query.empty()) {
5607 result = contacts_hints_.search_empty(limit);
5608 } else {
5609 result = contacts_hints_.search(query, limit);
5610 }
5611
5612 vector<UserId> user_ids;
5613 user_ids.reserve(result.second.size());
5614 for (auto key : result.second) {
5615 user_ids.emplace_back(key);
5616 }
5617
5618 promise.set_value(Unit());
5619 return {narrow_cast<int32>(result.first), std::move(user_ids)};
5620 }
5621
share_phone_number(UserId user_id,Promise<Unit> && promise)5622 void ContactsManager::share_phone_number(UserId user_id, Promise<Unit> &&promise) {
5623 TRY_STATUS_PROMISE(promise, G()->close_status());
5624
5625 if (!are_contacts_loaded_) {
5626 load_contacts(PromiseCreator::lambda(
5627 [actor_id = actor_id(this), user_id, promise = std::move(promise)](Result<Unit> &&) mutable {
5628 send_closure(actor_id, &ContactsManager::share_phone_number, user_id, std::move(promise));
5629 }));
5630 return;
5631 }
5632
5633 LOG(INFO) << "Share phone number with " << user_id;
5634 auto input_user = get_input_user(user_id);
5635 if (input_user == nullptr) {
5636 return promise.set_error(Status::Error(400, "User not found"));
5637 }
5638
5639 td_->messages_manager_->hide_dialog_action_bar(DialogId(user_id));
5640
5641 td_->create_handler<AcceptContactQuery>(std::move(promise))->send(user_id, std::move(input_user));
5642 }
5643
search_dialogs_nearby(const Location & location,Promise<td_api::object_ptr<td_api::chatsNearby>> && promise)5644 void ContactsManager::search_dialogs_nearby(const Location &location,
5645 Promise<td_api::object_ptr<td_api::chatsNearby>> &&promise) {
5646 if (location.empty()) {
5647 return promise.set_error(Status::Error(400, "Invalid location specified"));
5648 }
5649 last_user_location_ = location;
5650 try_send_set_location_visibility_query();
5651
5652 auto query_promise = PromiseCreator::lambda([actor_id = actor_id(this), promise = std::move(promise)](
5653 Result<tl_object_ptr<telegram_api::Updates>> result) mutable {
5654 send_closure(actor_id, &ContactsManager::on_get_dialogs_nearby, std::move(result), std::move(promise));
5655 });
5656 td_->create_handler<SearchDialogsNearbyQuery>(std::move(query_promise))->send(location, false, -1);
5657 }
5658
get_chats_nearby_object(const vector<DialogNearby> & dialogs_nearby)5659 vector<td_api::object_ptr<td_api::chatNearby>> ContactsManager::get_chats_nearby_object(
5660 const vector<DialogNearby> &dialogs_nearby) {
5661 return transform(dialogs_nearby, [](const DialogNearby &dialog_nearby) {
5662 return td_api::make_object<td_api::chatNearby>(dialog_nearby.dialog_id.get(), dialog_nearby.distance);
5663 });
5664 }
5665
send_update_users_nearby() const5666 void ContactsManager::send_update_users_nearby() const {
5667 send_closure(G()->td(), &Td::send_update,
5668 td_api::make_object<td_api::updateUsersNearby>(get_chats_nearby_object(users_nearby_)));
5669 }
5670
on_get_dialogs_nearby(Result<tl_object_ptr<telegram_api::Updates>> result,Promise<td_api::object_ptr<td_api::chatsNearby>> && promise)5671 void ContactsManager::on_get_dialogs_nearby(Result<tl_object_ptr<telegram_api::Updates>> result,
5672 Promise<td_api::object_ptr<td_api::chatsNearby>> &&promise) {
5673 if (result.is_error()) {
5674 return promise.set_error(result.move_as_error());
5675 }
5676
5677 auto updates_ptr = result.move_as_ok();
5678 if (updates_ptr->get_id() != telegram_api::updates::ID) {
5679 LOG(ERROR) << "Receive " << oneline(to_string(*updates_ptr)) << " instead of updates";
5680 return promise.set_error(Status::Error(500, "Receive unsupported response from the server"));
5681 }
5682
5683 auto update = telegram_api::move_object_as<telegram_api::updates>(updates_ptr);
5684 LOG(INFO) << "Receive chats nearby in " << to_string(update);
5685
5686 on_get_users(std::move(update->users_), "on_get_dialogs_nearby");
5687 on_get_chats(std::move(update->chats_), "on_get_dialogs_nearby");
5688
5689 for (auto &dialog_nearby : users_nearby_) {
5690 user_nearby_timeout_.cancel_timeout(dialog_nearby.dialog_id.get_user_id().get());
5691 }
5692 auto old_users_nearby = std::move(users_nearby_);
5693 users_nearby_.clear();
5694 channels_nearby_.clear();
5695 int32 location_visibility_expire_date = 0;
5696 for (auto &update_ptr : update->updates_) {
5697 if (update_ptr->get_id() != telegram_api::updatePeerLocated::ID) {
5698 LOG(ERROR) << "Receive unexpected " << to_string(update);
5699 continue;
5700 }
5701
5702 auto expire_date = on_update_peer_located(
5703 std::move(static_cast<telegram_api::updatePeerLocated *>(update_ptr.get())->peers_), false);
5704 if (expire_date != -1) {
5705 location_visibility_expire_date = expire_date;
5706 }
5707 }
5708 if (location_visibility_expire_date != location_visibility_expire_date_) {
5709 set_location_visibility_expire_date(location_visibility_expire_date);
5710 update_is_location_visible();
5711 }
5712
5713 std::sort(users_nearby_.begin(), users_nearby_.end());
5714 if (old_users_nearby != users_nearby_) {
5715 send_update_users_nearby(); // for other clients connected to the same TDLib instance
5716 }
5717 promise.set_value(td_api::make_object<td_api::chatsNearby>(get_chats_nearby_object(users_nearby_),
5718 get_chats_nearby_object(channels_nearby_)));
5719 }
5720
set_location(const Location & location,Promise<Unit> && promise)5721 void ContactsManager::set_location(const Location &location, Promise<Unit> &&promise) {
5722 if (location.empty()) {
5723 return promise.set_error(Status::Error(400, "Invalid location specified"));
5724 }
5725 last_user_location_ = location;
5726 try_send_set_location_visibility_query();
5727
5728 auto query_promise = PromiseCreator::lambda(
5729 [promise = std::move(promise)](Result<tl_object_ptr<telegram_api::Updates>> result) mutable {
5730 promise.set_value(Unit());
5731 });
5732 td_->create_handler<SearchDialogsNearbyQuery>(std::move(query_promise))->send(location, true, -1);
5733 }
5734
set_location_visibility()5735 void ContactsManager::set_location_visibility() {
5736 bool is_location_visible = G()->shared_config().get_option_boolean("is_location_visible");
5737 auto pending_location_visibility_expire_date = is_location_visible ? std::numeric_limits<int32>::max() : 0;
5738 if (pending_location_visibility_expire_date_ == -1 &&
5739 pending_location_visibility_expire_date == location_visibility_expire_date_) {
5740 return;
5741 }
5742 if (pending_location_visibility_expire_date_ != pending_location_visibility_expire_date) {
5743 pending_location_visibility_expire_date_ = pending_location_visibility_expire_date;
5744 G()->td_db()->get_binlog_pmc()->set("pending_location_visibility_expire_date",
5745 to_string(pending_location_visibility_expire_date));
5746 update_is_location_visible();
5747 }
5748 try_send_set_location_visibility_query();
5749 }
5750
try_send_set_location_visibility_query()5751 void ContactsManager::try_send_set_location_visibility_query() {
5752 if (G()->close_flag()) {
5753 return;
5754 }
5755 if (pending_location_visibility_expire_date_ == -1) {
5756 return;
5757 }
5758
5759 if (is_set_location_visibility_request_sent_) {
5760 return;
5761 }
5762 if (pending_location_visibility_expire_date_ != 0 && last_user_location_.empty()) {
5763 return;
5764 }
5765
5766 is_set_location_visibility_request_sent_ = true;
5767 auto query_promise =
5768 PromiseCreator::lambda([actor_id = actor_id(this), set_expire_date = pending_location_visibility_expire_date_](
5769 Result<tl_object_ptr<telegram_api::Updates>> result) {
5770 send_closure(actor_id, &ContactsManager::on_set_location_visibility_expire_date, set_expire_date,
5771 result.is_ok() ? 0 : result.error().code());
5772 });
5773 td_->create_handler<SearchDialogsNearbyQuery>(std::move(query_promise))
5774 ->send(last_user_location_, true, pending_location_visibility_expire_date_);
5775 }
5776
on_set_location_visibility_expire_date(int32 set_expire_date,int32 error_code)5777 void ContactsManager::on_set_location_visibility_expire_date(int32 set_expire_date, int32 error_code) {
5778 bool success = error_code == 0;
5779 is_set_location_visibility_request_sent_ = false;
5780
5781 if (set_expire_date != pending_location_visibility_expire_date_) {
5782 try_send_set_location_visibility_query();
5783 return;
5784 }
5785
5786 if (success) {
5787 set_location_visibility_expire_date(pending_location_visibility_expire_date_);
5788 } else {
5789 if (G()->close_flag()) {
5790 // request will be re-sent after restart
5791 return;
5792 }
5793 if (error_code != 406) {
5794 LOG(ERROR) << "Failed to set location visibility expire date to " << pending_location_visibility_expire_date_;
5795 }
5796 }
5797 G()->td_db()->get_binlog_pmc()->erase("pending_location_visibility_expire_date");
5798 pending_location_visibility_expire_date_ = -1;
5799 update_is_location_visible();
5800 }
5801
get_is_location_visible(Promise<Unit> && promise)5802 void ContactsManager::get_is_location_visible(Promise<Unit> &&promise) {
5803 auto query_promise = PromiseCreator::lambda([actor_id = actor_id(this), promise = std::move(promise)](
5804 Result<tl_object_ptr<telegram_api::Updates>> result) mutable {
5805 send_closure(actor_id, &ContactsManager::on_get_is_location_visible, std::move(result), std::move(promise));
5806 });
5807 td_->create_handler<SearchDialogsNearbyQuery>(std::move(query_promise))->send(Location(), true, -1);
5808 }
5809
on_get_is_location_visible(Result<tl_object_ptr<telegram_api::Updates>> && result,Promise<Unit> && promise)5810 void ContactsManager::on_get_is_location_visible(Result<tl_object_ptr<telegram_api::Updates>> &&result,
5811 Promise<Unit> &&promise) {
5812 TRY_STATUS_PROMISE(promise, G()->close_status());
5813 if (result.is_error()) {
5814 if (result.error().message() == "GEO_POINT_INVALID" && pending_location_visibility_expire_date_ == -1 &&
5815 location_visibility_expire_date_ > 0) {
5816 set_location_visibility_expire_date(0);
5817 update_is_location_visible();
5818 }
5819 return promise.set_value(Unit());
5820 }
5821
5822 auto updates_ptr = result.move_as_ok();
5823 if (updates_ptr->get_id() != telegram_api::updates::ID) {
5824 LOG(ERROR) << "Receive " << oneline(to_string(*updates_ptr)) << " instead of updates";
5825 return promise.set_value(Unit());
5826 }
5827
5828 auto updates = std::move(telegram_api::move_object_as<telegram_api::updates>(updates_ptr)->updates_);
5829 if (updates.size() != 1 || updates[0]->get_id() != telegram_api::updatePeerLocated::ID) {
5830 LOG(ERROR) << "Receive unexpected " << to_string(updates);
5831 return promise.set_value(Unit());
5832 }
5833
5834 auto peers = std::move(static_cast<telegram_api::updatePeerLocated *>(updates[0].get())->peers_);
5835 if (peers.size() != 1 || peers[0]->get_id() != telegram_api::peerSelfLocated::ID) {
5836 LOG(ERROR) << "Receive unexpected " << to_string(peers);
5837 return promise.set_value(Unit());
5838 }
5839
5840 auto location_visibility_expire_date = static_cast<telegram_api::peerSelfLocated *>(peers[0].get())->expires_;
5841 if (location_visibility_expire_date != location_visibility_expire_date_) {
5842 set_location_visibility_expire_date(location_visibility_expire_date);
5843 update_is_location_visible();
5844 }
5845
5846 promise.set_value(Unit());
5847 }
5848
on_update_peer_located(vector<tl_object_ptr<telegram_api::PeerLocated>> && peers,bool from_update)5849 int32 ContactsManager::on_update_peer_located(vector<tl_object_ptr<telegram_api::PeerLocated>> &&peers,
5850 bool from_update) {
5851 auto now = G()->unix_time();
5852 bool need_update = false;
5853 int32 location_visibility_expire_date = -1;
5854 for (auto &peer_located_ptr : peers) {
5855 if (peer_located_ptr->get_id() == telegram_api::peerSelfLocated::ID) {
5856 auto peer_self_located = telegram_api::move_object_as<telegram_api::peerSelfLocated>(peer_located_ptr);
5857 if (peer_self_located->expires_ == 0 || peer_self_located->expires_ > G()->unix_time()) {
5858 location_visibility_expire_date = peer_self_located->expires_;
5859 }
5860 continue;
5861 }
5862
5863 CHECK(peer_located_ptr->get_id() == telegram_api::peerLocated::ID);
5864 auto peer_located = telegram_api::move_object_as<telegram_api::peerLocated>(peer_located_ptr);
5865 DialogId dialog_id(peer_located->peer_);
5866 int32 expires_at = peer_located->expires_;
5867 int32 distance = peer_located->distance_;
5868 if (distance < 0 || distance > 50000000) {
5869 LOG(ERROR) << "Receive wrong distance to " << to_string(peer_located);
5870 continue;
5871 }
5872 if (expires_at <= now) {
5873 LOG(INFO) << "Skip expired result " << to_string(peer_located);
5874 continue;
5875 }
5876
5877 auto dialog_type = dialog_id.get_type();
5878 if (dialog_type == DialogType::User) {
5879 auto user_id = dialog_id.get_user_id();
5880 if (!have_user(user_id)) {
5881 LOG(ERROR) << "Can't find " << user_id;
5882 continue;
5883 }
5884 if (expires_at < now + 86400) {
5885 user_nearby_timeout_.set_timeout_in(user_id.get(), expires_at - now + 1);
5886 }
5887 } else if (dialog_type == DialogType::Channel) {
5888 auto channel_id = dialog_id.get_channel_id();
5889 if (!have_channel(channel_id)) {
5890 LOG(ERROR) << "Can't find " << channel_id;
5891 continue;
5892 }
5893 if (expires_at != std::numeric_limits<int32>::max()) {
5894 LOG(ERROR) << "Receive expiring at " << expires_at << " group location in " << to_string(peer_located);
5895 }
5896 if (from_update) {
5897 LOG(ERROR) << "Receive nearby " << channel_id << " from update";
5898 continue;
5899 }
5900 } else {
5901 LOG(ERROR) << "Receive chat of wrong type in " << to_string(peer_located);
5902 continue;
5903 }
5904
5905 td_->messages_manager_->force_create_dialog(dialog_id, "on_update_peer_located");
5906
5907 if (from_update) {
5908 CHECK(dialog_type == DialogType::User);
5909 bool is_found = false;
5910 for (auto &dialog_nearby : users_nearby_) {
5911 if (dialog_nearby.dialog_id == dialog_id) {
5912 if (dialog_nearby.distance != distance) {
5913 dialog_nearby.distance = distance;
5914 need_update = true;
5915 }
5916 is_found = true;
5917 break;
5918 }
5919 }
5920 if (!is_found) {
5921 users_nearby_.emplace_back(dialog_id, distance);
5922 all_users_nearby_.insert(dialog_id.get_user_id());
5923 need_update = true;
5924 }
5925 } else {
5926 if (dialog_type == DialogType::User) {
5927 users_nearby_.emplace_back(dialog_id, distance);
5928 all_users_nearby_.insert(dialog_id.get_user_id());
5929 } else {
5930 channels_nearby_.emplace_back(dialog_id, distance);
5931 }
5932 }
5933 }
5934 if (need_update) {
5935 std::sort(users_nearby_.begin(), users_nearby_.end());
5936 send_update_users_nearby();
5937 }
5938 return location_visibility_expire_date;
5939 }
5940
set_location_visibility_expire_date(int32 expire_date)5941 void ContactsManager::set_location_visibility_expire_date(int32 expire_date) {
5942 if (location_visibility_expire_date_ == expire_date) {
5943 return;
5944 }
5945
5946 LOG(INFO) << "Set set_location_visibility_expire_date to " << expire_date;
5947 location_visibility_expire_date_ = expire_date;
5948 if (expire_date == 0) {
5949 G()->td_db()->get_binlog_pmc()->erase("location_visibility_expire_date");
5950 } else {
5951 G()->td_db()->get_binlog_pmc()->set("location_visibility_expire_date", to_string(expire_date));
5952 }
5953 // the caller must call update_is_location_visible() itself
5954 }
5955
update_is_location_visible()5956 void ContactsManager::update_is_location_visible() {
5957 auto expire_date = pending_location_visibility_expire_date_ != -1 ? pending_location_visibility_expire_date_
5958 : location_visibility_expire_date_;
5959 G()->shared_config().set_option_boolean("is_location_visible", expire_date != 0);
5960 }
5961
on_update_bot_commands(DialogId dialog_id,UserId bot_user_id,vector<tl_object_ptr<telegram_api::botCommand>> && bot_commands)5962 void ContactsManager::on_update_bot_commands(DialogId dialog_id, UserId bot_user_id,
5963 vector<tl_object_ptr<telegram_api::botCommand>> &&bot_commands) {
5964 if (!bot_user_id.is_valid()) {
5965 LOG(ERROR) << "Receive updateBotCOmmands about invalid " << bot_user_id;
5966 return;
5967 }
5968 if (!have_user(bot_user_id) || !is_user_bot(bot_user_id)) {
5969 return;
5970 }
5971 if (td_->auth_manager_->is_bot()) {
5972 return;
5973 }
5974
5975 auto is_from_bot = [bot_user_id](const BotCommands &commands) {
5976 return commands.get_bot_user_id() == bot_user_id;
5977 };
5978
5979 switch (dialog_id.get_type()) {
5980 case DialogType::User: {
5981 UserId user_id(dialog_id.get_user_id());
5982 auto user_full = get_user_full(user_id);
5983 if (user_full != nullptr) {
5984 on_update_user_full_commands(user_full, user_id, std::move(bot_commands));
5985 update_user_full(user_full, user_id, "on_update_bot_commands");
5986 }
5987 break;
5988 }
5989 case DialogType::Chat: {
5990 ChatId chat_id(dialog_id.get_chat_id());
5991 auto chat_full = get_chat_full(chat_id);
5992 if (chat_full != nullptr) {
5993 if (bot_commands.empty()) {
5994 if (td::remove_if(chat_full->bot_commands, is_from_bot)) {
5995 chat_full->is_changed = true;
5996 }
5997 } else {
5998 BotCommands commands(bot_user_id, std::move(bot_commands));
5999 auto it = std::find_if(chat_full->bot_commands.begin(), chat_full->bot_commands.end(), is_from_bot);
6000 if (it != chat_full->bot_commands.end()) {
6001 if (*it != commands) {
6002 *it = std::move(commands);
6003 chat_full->is_changed = true;
6004 }
6005 } else {
6006 chat_full->bot_commands.push_back(std::move(commands));
6007 chat_full->is_changed = true;
6008 }
6009 }
6010 update_chat_full(chat_full, chat_id, "on_update_bot_commands");
6011 }
6012 break;
6013 }
6014 case DialogType::Channel: {
6015 ChannelId channel_id(dialog_id.get_channel_id());
6016 auto channel_full = get_channel_full(channel_id, true, "on_update_bot_commands");
6017 if (channel_full != nullptr) {
6018 if (bot_commands.empty()) {
6019 if (td::remove_if(channel_full->bot_commands, is_from_bot)) {
6020 channel_full->is_changed = true;
6021 }
6022 } else {
6023 BotCommands commands(bot_user_id, std::move(bot_commands));
6024 auto it = std::find_if(channel_full->bot_commands.begin(), channel_full->bot_commands.end(), is_from_bot);
6025 if (it != channel_full->bot_commands.end()) {
6026 if (*it != commands) {
6027 *it = std::move(commands);
6028 channel_full->is_changed = true;
6029 }
6030 } else {
6031 channel_full->bot_commands.push_back(std::move(commands));
6032 channel_full->is_changed = true;
6033 }
6034 }
6035 update_channel_full(channel_full, channel_id, "on_update_bot_commands");
6036 }
6037 break;
6038 }
6039 case DialogType::SecretChat:
6040 default:
6041 LOG(ERROR) << "Receive updateBotCommands in " << dialog_id;
6042 break;
6043 }
6044 }
6045
get_profile_photo_file_id(int64 photo_id) const6046 FileId ContactsManager::get_profile_photo_file_id(int64 photo_id) const {
6047 auto it = my_photo_file_id_.find(photo_id);
6048 if (it == my_photo_file_id_.end()) {
6049 return FileId();
6050 }
6051 return it->second;
6052 }
6053
set_profile_photo(const td_api::object_ptr<td_api::InputChatPhoto> & input_photo,Promise<Unit> && promise)6054 void ContactsManager::set_profile_photo(const td_api::object_ptr<td_api::InputChatPhoto> &input_photo,
6055 Promise<Unit> &&promise) {
6056 if (input_photo == nullptr) {
6057 return promise.set_error(Status::Error(400, "New profile photo must be non-empty"));
6058 }
6059
6060 const td_api::object_ptr<td_api::InputFile> *input_file = nullptr;
6061 double main_frame_timestamp = 0.0;
6062 bool is_animation = false;
6063 switch (input_photo->get_id()) {
6064 case td_api::inputChatPhotoPrevious::ID: {
6065 auto photo = static_cast<const td_api::inputChatPhotoPrevious *>(input_photo.get());
6066 auto photo_id = photo->chat_photo_id_;
6067 auto *u = get_user(get_my_id());
6068 if (u != nullptr && u->photo.id > 0 && photo_id == u->photo.id) {
6069 return promise.set_value(Unit());
6070 }
6071
6072 auto file_id = get_profile_photo_file_id(photo_id);
6073 if (!file_id.is_valid()) {
6074 return promise.set_error(Status::Error(400, "Unknown profile photo ID specified"));
6075 }
6076 return send_update_profile_photo_query(td_->file_manager_->dup_file_id(file_id), photo_id, std::move(promise));
6077 }
6078 case td_api::inputChatPhotoStatic::ID: {
6079 auto photo = static_cast<const td_api::inputChatPhotoStatic *>(input_photo.get());
6080 input_file = &photo->photo_;
6081 break;
6082 }
6083 case td_api::inputChatPhotoAnimation::ID: {
6084 auto photo = static_cast<const td_api::inputChatPhotoAnimation *>(input_photo.get());
6085 input_file = &photo->animation_;
6086 main_frame_timestamp = photo->main_frame_timestamp_;
6087 is_animation = true;
6088 break;
6089 }
6090 default:
6091 UNREACHABLE();
6092 break;
6093 }
6094
6095 const double MAX_ANIMATION_DURATION = 10.0;
6096 if (main_frame_timestamp < 0.0 || main_frame_timestamp > MAX_ANIMATION_DURATION) {
6097 return promise.set_error(Status::Error(400, "Wrong main frame timestamp specified"));
6098 }
6099
6100 auto file_type = is_animation ? FileType::Animation : FileType::Photo;
6101 auto r_file_id = td_->file_manager_->get_input_file_id(file_type, *input_file, DialogId(get_my_id()), false, false);
6102 if (r_file_id.is_error()) {
6103 // TODO promise.set_error(std::move(status));
6104 return promise.set_error(Status::Error(400, r_file_id.error().message()));
6105 }
6106 FileId file_id = r_file_id.ok();
6107 CHECK(file_id.is_valid());
6108
6109 upload_profile_photo(td_->file_manager_->dup_file_id(file_id), is_animation, main_frame_timestamp,
6110 std::move(promise));
6111 }
6112
send_update_profile_photo_query(FileId file_id,int64 old_photo_id,Promise<Unit> && promise)6113 void ContactsManager::send_update_profile_photo_query(FileId file_id, int64 old_photo_id, Promise<Unit> &&promise) {
6114 FileView file_view = td_->file_manager_->get_file_view(file_id);
6115 td_->create_handler<UpdateProfilePhotoQuery>(std::move(promise))
6116 ->send(file_id, old_photo_id, file_view.main_remote_location().as_input_photo());
6117 }
6118
upload_profile_photo(FileId file_id,bool is_animation,double main_frame_timestamp,Promise<Unit> && promise,int reupload_count,vector<int> bad_parts)6119 void ContactsManager::upload_profile_photo(FileId file_id, bool is_animation, double main_frame_timestamp,
6120 Promise<Unit> &&promise, int reupload_count, vector<int> bad_parts) {
6121 CHECK(file_id.is_valid());
6122 CHECK(uploaded_profile_photos_.find(file_id) == uploaded_profile_photos_.end());
6123 uploaded_profile_photos_.emplace(
6124 file_id, UploadedProfilePhoto{main_frame_timestamp, is_animation, reupload_count, std::move(promise)});
6125 LOG(INFO) << "Ask to upload " << (is_animation ? "animated" : "static") << " profile photo " << file_id
6126 << " with bad parts " << bad_parts;
6127 // TODO use force_reupload if reupload_count >= 1, replace reupload_count with is_reupload
6128 td_->file_manager_->resume_upload(file_id, std::move(bad_parts), upload_profile_photo_callback_, 32, 0);
6129 }
6130
delete_profile_photo(int64 profile_photo_id,Promise<Unit> && promise)6131 void ContactsManager::delete_profile_photo(int64 profile_photo_id, Promise<Unit> &&promise) {
6132 const User *u = get_user(get_my_id());
6133 if (u != nullptr && u->photo.id == profile_photo_id) {
6134 td_->create_handler<UpdateProfilePhotoQuery>(std::move(promise))
6135 ->send(FileId(), profile_photo_id, make_tl_object<telegram_api::inputPhotoEmpty>());
6136 return;
6137 }
6138
6139 td_->create_handler<DeleteProfilePhotoQuery>(std::move(promise))->send(profile_photo_id);
6140 }
6141
set_name(const string & first_name,const string & last_name,Promise<Unit> && promise)6142 void ContactsManager::set_name(const string &first_name, const string &last_name, Promise<Unit> &&promise) {
6143 auto new_first_name = clean_name(first_name, MAX_NAME_LENGTH);
6144 auto new_last_name = clean_name(last_name, MAX_NAME_LENGTH);
6145 if (new_first_name.empty()) {
6146 return promise.set_error(Status::Error(400, "First name must be non-empty"));
6147 }
6148
6149 const User *u = get_user(get_my_id());
6150 int32 flags = 0;
6151 // TODO we can already send request for changing first_name and last_name and wanting to set initial values
6152 // TODO need to be rewritten using invoke after and cancelling previous request
6153 if (u == nullptr || u->first_name != new_first_name) {
6154 flags |= ACCOUNT_UPDATE_FIRST_NAME;
6155 }
6156 if (u == nullptr || u->last_name != new_last_name) {
6157 flags |= ACCOUNT_UPDATE_LAST_NAME;
6158 }
6159 if (flags == 0) {
6160 return promise.set_value(Unit());
6161 }
6162
6163 td_->create_handler<UpdateProfileQuery>(std::move(promise))->send(flags, new_first_name, new_last_name, "");
6164 }
6165
set_bio(const string & bio,Promise<Unit> && promise)6166 void ContactsManager::set_bio(const string &bio, Promise<Unit> &&promise) {
6167 auto new_bio = strip_empty_characters(bio, MAX_BIO_LENGTH);
6168 for (auto &c : new_bio) {
6169 if (c == '\n') {
6170 c = ' ';
6171 }
6172 }
6173
6174 const UserFull *user_full = get_user_full(get_my_id());
6175 int32 flags = 0;
6176 // TODO we can already send request for changing bio and wanting to set initial values
6177 // TODO need to be rewritten using invoke after and cancelling previous request
6178 if (user_full == nullptr || user_full->about != new_bio) {
6179 flags |= ACCOUNT_UPDATE_ABOUT;
6180 }
6181 if (flags == 0) {
6182 return promise.set_value(Unit());
6183 }
6184
6185 td_->create_handler<UpdateProfileQuery>(std::move(promise))->send(flags, "", "", new_bio);
6186 }
6187
on_update_profile_success(int32 flags,const string & first_name,const string & last_name,const string & about)6188 void ContactsManager::on_update_profile_success(int32 flags, const string &first_name, const string &last_name,
6189 const string &about) {
6190 CHECK(flags != 0);
6191
6192 auto my_user_id = get_my_id();
6193 const User *u = get_user(my_user_id);
6194 if (u == nullptr) {
6195 LOG(ERROR) << "Doesn't receive info about me during update profile";
6196 return;
6197 }
6198 LOG_IF(ERROR, (flags & ACCOUNT_UPDATE_FIRST_NAME) != 0 && u->first_name != first_name)
6199 << "Wrong first name \"" << u->first_name << "\", expected \"" << first_name << '"';
6200 LOG_IF(ERROR, (flags & ACCOUNT_UPDATE_LAST_NAME) != 0 && u->last_name != last_name)
6201 << "Wrong last name \"" << u->last_name << "\", expected \"" << last_name << '"';
6202
6203 if ((flags & ACCOUNT_UPDATE_ABOUT) != 0) {
6204 UserFull *user_full = get_user_full_force(my_user_id);
6205 if (user_full != nullptr) {
6206 user_full->about = about;
6207 user_full->is_changed = true;
6208 update_user_full(user_full, my_user_id, "on_update_profile_success");
6209 td_->group_call_manager_->on_update_dialog_about(DialogId(my_user_id), user_full->about, true);
6210 }
6211 }
6212 }
6213
set_username(const string & username,Promise<Unit> && promise)6214 void ContactsManager::set_username(const string &username, Promise<Unit> &&promise) {
6215 if (!username.empty() && !is_valid_username(username)) {
6216 return promise.set_error(Status::Error(400, "Username is invalid"));
6217 }
6218 td_->create_handler<UpdateUsernameQuery>(std::move(promise))->send(username);
6219 }
6220
set_chat_description(ChatId chat_id,const string & description,Promise<Unit> && promise)6221 void ContactsManager::set_chat_description(ChatId chat_id, const string &description, Promise<Unit> &&promise) {
6222 auto new_description = strip_empty_characters(description, MAX_DESCRIPTION_LENGTH);
6223 auto c = get_chat(chat_id);
6224 if (c == nullptr) {
6225 return promise.set_error(Status::Error(400, "Chat info not found"));
6226 }
6227 if (!get_chat_permissions(c).can_change_info_and_settings()) {
6228 return promise.set_error(Status::Error(400, "Not enough rights to set chat description"));
6229 }
6230
6231 td_->create_handler<EditChatAboutQuery>(std::move(promise))->send(DialogId(chat_id), new_description);
6232 }
6233
set_channel_username(ChannelId channel_id,const string & username,Promise<Unit> && promise)6234 void ContactsManager::set_channel_username(ChannelId channel_id, const string &username, Promise<Unit> &&promise) {
6235 auto c = get_channel(channel_id);
6236 if (c == nullptr) {
6237 return promise.set_error(Status::Error(400, "Supergroup not found"));
6238 }
6239 if (!get_channel_status(c).is_creator()) {
6240 return promise.set_error(Status::Error(400, "Not enough rights to change supergroup username"));
6241 }
6242
6243 if (!username.empty() && !is_valid_username(username)) {
6244 return promise.set_error(Status::Error(400, "Username is invalid"));
6245 }
6246
6247 if (!username.empty() && c->username.empty()) {
6248 auto channel_full = get_channel_full(channel_id, false, "set_channel_username");
6249 if (channel_full != nullptr && !channel_full->can_set_username) {
6250 return promise.set_error(Status::Error(400, "Can't set supergroup username"));
6251 }
6252 }
6253
6254 td_->create_handler<UpdateChannelUsernameQuery>(std::move(promise))->send(channel_id, username);
6255 }
6256
set_channel_sticker_set(ChannelId channel_id,StickerSetId sticker_set_id,Promise<Unit> && promise)6257 void ContactsManager::set_channel_sticker_set(ChannelId channel_id, StickerSetId sticker_set_id,
6258 Promise<Unit> &&promise) {
6259 auto c = get_channel(channel_id);
6260 if (c == nullptr) {
6261 return promise.set_error(Status::Error(400, "Supergroup not found"));
6262 }
6263 if (!c->is_megagroup) {
6264 return promise.set_error(Status::Error(400, "Chat sticker set can be set only for supergroups"));
6265 }
6266 if (!get_channel_permissions(c).can_change_info_and_settings()) {
6267 return promise.set_error(Status::Error(400, "Not enough rights to change supergroup sticker set"));
6268 }
6269
6270 telegram_api::object_ptr<telegram_api::InputStickerSet> input_sticker_set;
6271 if (!sticker_set_id.is_valid()) {
6272 input_sticker_set = telegram_api::make_object<telegram_api::inputStickerSetEmpty>();
6273 } else {
6274 input_sticker_set = td_->stickers_manager_->get_input_sticker_set(sticker_set_id);
6275 if (input_sticker_set == nullptr) {
6276 return promise.set_error(Status::Error(400, "Sticker set not found"));
6277 }
6278 }
6279
6280 auto channel_full = get_channel_full(channel_id, false, "set_channel_sticker_set");
6281 if (channel_full != nullptr && !channel_full->can_set_sticker_set) {
6282 return promise.set_error(Status::Error(400, "Can't set supergroup sticker set"));
6283 }
6284
6285 td_->create_handler<SetChannelStickerSetQuery>(std::move(promise))
6286 ->send(channel_id, sticker_set_id, std::move(input_sticker_set));
6287 }
6288
toggle_channel_sign_messages(ChannelId channel_id,bool sign_messages,Promise<Unit> && promise)6289 void ContactsManager::toggle_channel_sign_messages(ChannelId channel_id, bool sign_messages, Promise<Unit> &&promise) {
6290 auto c = get_channel(channel_id);
6291 if (c == nullptr) {
6292 return promise.set_error(Status::Error(400, "Supergroup not found"));
6293 }
6294 if (get_channel_type(c) == ChannelType::Megagroup) {
6295 return promise.set_error(Status::Error(400, "Message signatures can't be toggled in supergroups"));
6296 }
6297 if (!get_channel_permissions(c).can_change_info_and_settings()) {
6298 return promise.set_error(Status::Error(400, "Not enough rights to toggle channel sign messages"));
6299 }
6300
6301 td_->create_handler<ToggleChannelSignaturesQuery>(std::move(promise))->send(channel_id, sign_messages);
6302 }
6303
toggle_channel_is_all_history_available(ChannelId channel_id,bool is_all_history_available,Promise<Unit> && promise)6304 void ContactsManager::toggle_channel_is_all_history_available(ChannelId channel_id, bool is_all_history_available,
6305 Promise<Unit> &&promise) {
6306 auto c = get_channel(channel_id);
6307 if (c == nullptr) {
6308 return promise.set_error(Status::Error(400, "Supergroup not found"));
6309 }
6310 if (!get_channel_permissions(c).can_change_info_and_settings()) {
6311 return promise.set_error(Status::Error(400, "Not enough rights to toggle all supergroup history availability"));
6312 }
6313 if (get_channel_type(c) != ChannelType::Megagroup) {
6314 return promise.set_error(Status::Error(400, "Message history can be hidden in supergroups only"));
6315 }
6316 if (c->has_linked_channel && !is_all_history_available) {
6317 return promise.set_error(Status::Error(400, "Message history can't be hidden in discussion supergroups"));
6318 }
6319 // it can be toggled in public chats, but will not affect them
6320
6321 td_->create_handler<TogglePrehistoryHiddenQuery>(std::move(promise))->send(channel_id, is_all_history_available);
6322 }
6323
convert_channel_to_gigagroup(ChannelId channel_id,Promise<Unit> && promise)6324 void ContactsManager::convert_channel_to_gigagroup(ChannelId channel_id, Promise<Unit> &&promise) {
6325 auto c = get_channel(channel_id);
6326 if (c == nullptr) {
6327 return promise.set_error(Status::Error(400, "Supergroup not found"));
6328 }
6329 if (!get_channel_permissions(c).is_creator()) {
6330 return promise.set_error(Status::Error(400, "Not enough rights to convert group to broadcast group"));
6331 }
6332 if (get_channel_type(c) != ChannelType::Megagroup) {
6333 return promise.set_error(Status::Error(400, "Chat must be a supergroup"));
6334 }
6335
6336 remove_dialog_suggested_action(SuggestedAction{SuggestedAction::Type::ConvertToGigagroup, DialogId(channel_id)});
6337
6338 td_->create_handler<ConvertToGigagroupQuery>(std::move(promise))->send(channel_id);
6339 }
6340
set_channel_description(ChannelId channel_id,const string & description,Promise<Unit> && promise)6341 void ContactsManager::set_channel_description(ChannelId channel_id, const string &description,
6342 Promise<Unit> &&promise) {
6343 auto new_description = strip_empty_characters(description, MAX_DESCRIPTION_LENGTH);
6344 auto c = get_channel(channel_id);
6345 if (c == nullptr) {
6346 return promise.set_error(Status::Error(400, "Chat info not found"));
6347 }
6348 if (!get_channel_permissions(c).can_change_info_and_settings()) {
6349 return promise.set_error(Status::Error(400, "Not enough rights to set chat description"));
6350 }
6351
6352 td_->create_handler<EditChatAboutQuery>(std::move(promise))->send(DialogId(channel_id), new_description);
6353 }
6354
set_channel_discussion_group(DialogId dialog_id,DialogId discussion_dialog_id,Promise<Unit> && promise)6355 void ContactsManager::set_channel_discussion_group(DialogId dialog_id, DialogId discussion_dialog_id,
6356 Promise<Unit> &&promise) {
6357 if (!dialog_id.is_valid() && !discussion_dialog_id.is_valid()) {
6358 return promise.set_error(Status::Error(400, "Invalid chat identifiers specified"));
6359 }
6360
6361 ChannelId broadcast_channel_id;
6362 telegram_api::object_ptr<telegram_api::InputChannel> broadcast_input_channel;
6363 if (dialog_id.is_valid()) {
6364 if (!td_->messages_manager_->have_dialog_force(dialog_id, "set_channel_discussion_group 1")) {
6365 return promise.set_error(Status::Error(400, "Chat not found"));
6366 }
6367
6368 if (dialog_id.get_type() != DialogType::Channel) {
6369 return promise.set_error(Status::Error(400, "Chat is not a channel"));
6370 }
6371
6372 broadcast_channel_id = dialog_id.get_channel_id();
6373 const Channel *c = get_channel(broadcast_channel_id);
6374 if (c == nullptr) {
6375 return promise.set_error(Status::Error(400, "Chat info not found"));
6376 }
6377
6378 if (c->is_megagroup) {
6379 return promise.set_error(Status::Error(400, "Chat is not a channel"));
6380 }
6381 if (!c->status.is_administrator() || !c->status.can_change_info_and_settings()) {
6382 return promise.set_error(Status::Error(400, "Not enough rights in the channel"));
6383 }
6384
6385 broadcast_input_channel = get_input_channel(broadcast_channel_id);
6386 CHECK(broadcast_input_channel != nullptr);
6387 } else {
6388 broadcast_input_channel = telegram_api::make_object<telegram_api::inputChannelEmpty>();
6389 }
6390
6391 ChannelId group_channel_id;
6392 telegram_api::object_ptr<telegram_api::InputChannel> group_input_channel;
6393 if (discussion_dialog_id.is_valid()) {
6394 if (!td_->messages_manager_->have_dialog_force(discussion_dialog_id, "set_channel_discussion_group 2")) {
6395 return promise.set_error(Status::Error(400, "Discussion chat not found"));
6396 }
6397 if (discussion_dialog_id.get_type() != DialogType::Channel) {
6398 return promise.set_error(Status::Error(400, "Discussion chat is not a supergroup"));
6399 }
6400
6401 group_channel_id = discussion_dialog_id.get_channel_id();
6402 const Channel *c = get_channel(group_channel_id);
6403 if (c == nullptr) {
6404 return promise.set_error(Status::Error(400, "Discussion chat info not found"));
6405 }
6406
6407 if (!c->is_megagroup) {
6408 return promise.set_error(Status::Error(400, "Discussion chat is not a supergroup"));
6409 }
6410 if (!c->status.is_administrator() || !c->status.can_pin_messages()) {
6411 return promise.set_error(Status::Error(400, "Not enough rights in the supergroup"));
6412 }
6413
6414 group_input_channel = get_input_channel(group_channel_id);
6415 CHECK(group_input_channel != nullptr);
6416 } else {
6417 group_input_channel = telegram_api::make_object<telegram_api::inputChannelEmpty>();
6418 }
6419
6420 td_->create_handler<SetDiscussionGroupQuery>(std::move(promise))
6421 ->send(broadcast_channel_id, std::move(broadcast_input_channel), group_channel_id,
6422 std::move(group_input_channel));
6423 }
6424
set_channel_location(DialogId dialog_id,const DialogLocation & location,Promise<Unit> && promise)6425 void ContactsManager::set_channel_location(DialogId dialog_id, const DialogLocation &location,
6426 Promise<Unit> &&promise) {
6427 if (location.empty()) {
6428 return promise.set_error(Status::Error(400, "Invalid chat location specified"));
6429 }
6430
6431 if (!dialog_id.is_valid()) {
6432 return promise.set_error(Status::Error(400, "Invalid chat identifier specified"));
6433 }
6434 if (!td_->messages_manager_->have_dialog_force(dialog_id, "set_channel_location")) {
6435 return promise.set_error(Status::Error(400, "Chat not found"));
6436 }
6437
6438 if (dialog_id.get_type() != DialogType::Channel) {
6439 return promise.set_error(Status::Error(400, "Chat is not a supergroup"));
6440 }
6441
6442 auto channel_id = dialog_id.get_channel_id();
6443 const Channel *c = get_channel(channel_id);
6444 if (c == nullptr) {
6445 return promise.set_error(Status::Error(400, "Chat info not found"));
6446 }
6447 if (!c->is_megagroup) {
6448 return promise.set_error(Status::Error(400, "Chat is not a supergroup"));
6449 }
6450 if (!c->status.is_creator()) {
6451 return promise.set_error(Status::Error(400, "Not enough rights in the supergroup"));
6452 }
6453
6454 td_->create_handler<EditLocationQuery>(std::move(promise))->send(channel_id, location);
6455 }
6456
set_channel_slow_mode_delay(DialogId dialog_id,int32 slow_mode_delay,Promise<Unit> && promise)6457 void ContactsManager::set_channel_slow_mode_delay(DialogId dialog_id, int32 slow_mode_delay, Promise<Unit> &&promise) {
6458 vector<int32> allowed_slow_mode_delays{0, 10, 30, 60, 300, 900, 3600};
6459 if (!td::contains(allowed_slow_mode_delays, slow_mode_delay)) {
6460 return promise.set_error(Status::Error(400, "Invalid new value for slow mode delay"));
6461 }
6462
6463 if (!dialog_id.is_valid()) {
6464 return promise.set_error(Status::Error(400, "Invalid chat identifier specified"));
6465 }
6466 if (!td_->messages_manager_->have_dialog_force(dialog_id, "set_channel_slow_mode_delay")) {
6467 return promise.set_error(Status::Error(400, "Chat not found"));
6468 }
6469
6470 if (dialog_id.get_type() != DialogType::Channel) {
6471 return promise.set_error(Status::Error(400, "Chat is not a supergroup"));
6472 }
6473
6474 auto channel_id = dialog_id.get_channel_id();
6475 const Channel *c = get_channel(channel_id);
6476 if (c == nullptr) {
6477 return promise.set_error(Status::Error(400, "Chat info not found"));
6478 }
6479 if (!c->is_megagroup) {
6480 return promise.set_error(Status::Error(400, "Chat is not a supergroup"));
6481 }
6482 if (!get_channel_permissions(c).can_restrict_members()) {
6483 return promise.set_error(Status::Error(400, "Not enough rights in the supergroup"));
6484 }
6485
6486 td_->create_handler<ToggleSlowModeQuery>(std::move(promise))->send(channel_id, slow_mode_delay);
6487 }
6488
get_channel_statistics_dc_id(DialogId dialog_id,bool for_full_statistics,Promise<DcId> && promise)6489 void ContactsManager::get_channel_statistics_dc_id(DialogId dialog_id, bool for_full_statistics,
6490 Promise<DcId> &&promise) {
6491 if (!dialog_id.is_valid()) {
6492 return promise.set_error(Status::Error(400, "Invalid chat identifier specified"));
6493 }
6494 if (!td_->messages_manager_->have_dialog_force(dialog_id, "get_channel_statistics_dc_id")) {
6495 return promise.set_error(Status::Error(400, "Chat not found"));
6496 }
6497
6498 if (dialog_id.get_type() != DialogType::Channel) {
6499 return promise.set_error(Status::Error(400, "Chat is not a channel"));
6500 }
6501
6502 auto channel_id = dialog_id.get_channel_id();
6503 const Channel *c = get_channel(channel_id);
6504 if (c == nullptr) {
6505 return promise.set_error(Status::Error(400, "Chat info not found"));
6506 }
6507
6508 auto channel_full = get_channel_full_force(channel_id, false, "get_channel_statistics_dc_id");
6509 if (channel_full == nullptr || !channel_full->stats_dc_id.is_exact() ||
6510 (for_full_statistics && !channel_full->can_view_statistics)) {
6511 auto query_promise = PromiseCreator::lambda([actor_id = actor_id(this), channel_id, for_full_statistics,
6512 promise = std::move(promise)](Result<Unit> result) mutable {
6513 send_closure(actor_id, &ContactsManager::get_channel_statistics_dc_id_impl, channel_id, for_full_statistics,
6514 std::move(promise));
6515 });
6516 send_get_channel_full_query(channel_full, channel_id, std::move(query_promise), "get_channel_statistics_dc_id");
6517 return;
6518 }
6519
6520 promise.set_value(DcId(channel_full->stats_dc_id));
6521 }
6522
get_channel_statistics_dc_id_impl(ChannelId channel_id,bool for_full_statistics,Promise<DcId> && promise)6523 void ContactsManager::get_channel_statistics_dc_id_impl(ChannelId channel_id, bool for_full_statistics,
6524 Promise<DcId> &&promise) {
6525 TRY_STATUS_PROMISE(promise, G()->close_status());
6526
6527 auto channel_full = get_channel_full(channel_id, false, "get_channel_statistics_dc_id_impl");
6528 if (channel_full == nullptr) {
6529 return promise.set_error(Status::Error(400, "Chat full info not found"));
6530 }
6531
6532 if (!channel_full->stats_dc_id.is_exact() || (for_full_statistics && !channel_full->can_view_statistics)) {
6533 return promise.set_error(Status::Error(400, "Chat statistics is not available"));
6534 }
6535
6536 promise.set_value(DcId(channel_full->stats_dc_id));
6537 }
6538
get_channel_statistics(DialogId dialog_id,bool is_dark,Promise<td_api::object_ptr<td_api::ChatStatistics>> && promise)6539 void ContactsManager::get_channel_statistics(DialogId dialog_id, bool is_dark,
6540 Promise<td_api::object_ptr<td_api::ChatStatistics>> &&promise) {
6541 auto dc_id_promise = PromiseCreator::lambda(
6542 [actor_id = actor_id(this), dialog_id, is_dark, promise = std::move(promise)](Result<DcId> r_dc_id) mutable {
6543 if (r_dc_id.is_error()) {
6544 return promise.set_error(r_dc_id.move_as_error());
6545 }
6546 send_closure(actor_id, &ContactsManager::send_get_channel_stats_query, r_dc_id.move_as_ok(),
6547 dialog_id.get_channel_id(), is_dark, std::move(promise));
6548 });
6549 get_channel_statistics_dc_id(dialog_id, true, std::move(dc_id_promise));
6550 }
6551
send_get_channel_stats_query(DcId dc_id,ChannelId channel_id,bool is_dark,Promise<td_api::object_ptr<td_api::ChatStatistics>> && promise)6552 void ContactsManager::send_get_channel_stats_query(DcId dc_id, ChannelId channel_id, bool is_dark,
6553 Promise<td_api::object_ptr<td_api::ChatStatistics>> &&promise) {
6554 TRY_STATUS_PROMISE(promise, G()->close_status());
6555
6556 const Channel *c = get_channel(channel_id);
6557 CHECK(c != nullptr);
6558 if (c->is_megagroup) {
6559 td_->create_handler<GetMegagroupStatsQuery>(std::move(promise))->send(channel_id, is_dark, dc_id);
6560 } else {
6561 td_->create_handler<GetBroadcastStatsQuery>(std::move(promise))->send(channel_id, is_dark, dc_id);
6562 }
6563 }
6564
can_get_channel_message_statistics(DialogId dialog_id) const6565 bool ContactsManager::can_get_channel_message_statistics(DialogId dialog_id) const {
6566 if (dialog_id.get_type() != DialogType::Channel) {
6567 return false;
6568 }
6569
6570 auto channel_id = dialog_id.get_channel_id();
6571 const Channel *c = get_channel(channel_id);
6572 if (c == nullptr || c->is_megagroup) {
6573 return false;
6574 }
6575
6576 if (td_->auth_manager_->is_bot()) {
6577 return false;
6578 }
6579
6580 auto channel_full = get_channel_full(channel_id);
6581 if (channel_full != nullptr) {
6582 return channel_full->stats_dc_id.is_exact();
6583 }
6584
6585 return c->status.is_administrator();
6586 }
6587
get_channel_message_statistics(FullMessageId full_message_id,bool is_dark,Promise<td_api::object_ptr<td_api::messageStatistics>> && promise)6588 void ContactsManager::get_channel_message_statistics(FullMessageId full_message_id, bool is_dark,
6589 Promise<td_api::object_ptr<td_api::messageStatistics>> &&promise) {
6590 auto dc_id_promise = PromiseCreator::lambda([actor_id = actor_id(this), full_message_id, is_dark,
6591 promise = std::move(promise)](Result<DcId> r_dc_id) mutable {
6592 if (r_dc_id.is_error()) {
6593 return promise.set_error(r_dc_id.move_as_error());
6594 }
6595 send_closure(actor_id, &ContactsManager::send_get_channel_message_stats_query, r_dc_id.move_as_ok(),
6596 full_message_id, is_dark, std::move(promise));
6597 });
6598 get_channel_statistics_dc_id(full_message_id.get_dialog_id(), false, std::move(dc_id_promise));
6599 }
6600
send_get_channel_message_stats_query(DcId dc_id,FullMessageId full_message_id,bool is_dark,Promise<td_api::object_ptr<td_api::messageStatistics>> && promise)6601 void ContactsManager::send_get_channel_message_stats_query(
6602 DcId dc_id, FullMessageId full_message_id, bool is_dark,
6603 Promise<td_api::object_ptr<td_api::messageStatistics>> &&promise) {
6604 TRY_STATUS_PROMISE(promise, G()->close_status());
6605
6606 auto dialog_id = full_message_id.get_dialog_id();
6607 if (!td_->messages_manager_->have_message_force(full_message_id, "send_get_channel_message_stats_query")) {
6608 return promise.set_error(Status::Error(400, "Message not found"));
6609 }
6610 if (!td_->messages_manager_->can_get_message_statistics(full_message_id)) {
6611 return promise.set_error(Status::Error(400, "Message statistics is inaccessible"));
6612 }
6613 CHECK(dialog_id.get_type() == DialogType::Channel);
6614 td_->create_handler<GetMessageStatsQuery>(std::move(promise))
6615 ->send(dialog_id.get_channel_id(), full_message_id.get_message_id(), is_dark, dc_id);
6616 }
6617
load_statistics_graph(DialogId dialog_id,string token,int64 x,Promise<td_api::object_ptr<td_api::StatisticalGraph>> && promise)6618 void ContactsManager::load_statistics_graph(DialogId dialog_id, string token, int64 x,
6619 Promise<td_api::object_ptr<td_api::StatisticalGraph>> &&promise) {
6620 auto dc_id_promise = PromiseCreator::lambda([actor_id = actor_id(this), token = std::move(token), x,
6621 promise = std::move(promise)](Result<DcId> r_dc_id) mutable {
6622 if (r_dc_id.is_error()) {
6623 return promise.set_error(r_dc_id.move_as_error());
6624 }
6625 send_closure(actor_id, &ContactsManager::send_load_async_graph_query, r_dc_id.move_as_ok(), std::move(token), x,
6626 std::move(promise));
6627 });
6628 get_channel_statistics_dc_id(dialog_id, false, std::move(dc_id_promise));
6629 }
6630
send_load_async_graph_query(DcId dc_id,string token,int64 x,Promise<td_api::object_ptr<td_api::StatisticalGraph>> && promise)6631 void ContactsManager::send_load_async_graph_query(DcId dc_id, string token, int64 x,
6632 Promise<td_api::object_ptr<td_api::StatisticalGraph>> &&promise) {
6633 TRY_STATUS_PROMISE(promise, G()->close_status());
6634
6635 td_->create_handler<LoadAsyncGraphQuery>(std::move(promise))->send(token, x, dc_id);
6636 }
6637
report_channel_spam(ChannelId channel_id,const vector<MessageId> & message_ids,Promise<Unit> && promise)6638 void ContactsManager::report_channel_spam(ChannelId channel_id, const vector<MessageId> &message_ids,
6639 Promise<Unit> &&promise) {
6640 auto c = get_channel(channel_id);
6641 if (c == nullptr) {
6642 return promise.set_error(Status::Error(400, "Supergroup not found"));
6643 }
6644 if (!c->is_megagroup) {
6645 return promise.set_error(Status::Error(400, "Spam can be reported only in supergroups"));
6646 }
6647
6648 if (message_ids.empty()) {
6649 return promise.set_error(Status::Error(400, "Message list is empty"));
6650 }
6651
6652 DialogId sender_dialog_id;
6653 vector<MessageId> server_message_ids;
6654 for (auto &message_id : message_ids) {
6655 if (message_id.is_valid_scheduled()) {
6656 return promise.set_error(Status::Error(400, "Can't report scheduled messages"));
6657 }
6658
6659 if (!message_id.is_valid()) {
6660 return promise.set_error(Status::Error(400, "Message not found"));
6661 }
6662
6663 if (!message_id.is_server()) {
6664 continue;
6665 }
6666
6667 auto current_sender_dialog_id = td_->messages_manager_->get_message_sender({DialogId(channel_id), message_id});
6668 if (!current_sender_dialog_id.is_valid()) {
6669 continue;
6670 }
6671 if (sender_dialog_id.is_valid()) {
6672 if (current_sender_dialog_id != sender_dialog_id) {
6673 return promise.set_error(Status::Error(400, "All messages nust be from the same sender"));
6674 }
6675 } else {
6676 sender_dialog_id = current_sender_dialog_id;
6677 }
6678
6679 server_message_ids.push_back(message_id);
6680 }
6681 if (server_message_ids.empty()) {
6682 return promise.set_value(Unit());
6683 }
6684 CHECK(sender_dialog_id.is_valid());
6685
6686 if (!td_->messages_manager_->have_input_peer(sender_dialog_id, AccessRights::Know)) {
6687 return promise.set_error(Status::Error(400, "Have no access to the user"));
6688 }
6689 if (sender_dialog_id == DialogId(get_my_id())) {
6690 return promise.set_error(Status::Error(400, "Can't report self"));
6691 }
6692
6693 td_->create_handler<ReportChannelSpamQuery>(std::move(promise))
6694 ->send(channel_id, sender_dialog_id, server_message_ids);
6695 }
6696
delete_chat(ChatId chat_id,Promise<Unit> && promise)6697 void ContactsManager::delete_chat(ChatId chat_id, Promise<Unit> &&promise) {
6698 auto c = get_chat(chat_id);
6699 if (c == nullptr) {
6700 return promise.set_error(Status::Error(400, "Chat info not found"));
6701 }
6702 if (!get_chat_status(c).is_creator()) {
6703 return promise.set_error(Status::Error(400, "Not enough rights to delete the chat"));
6704 }
6705 if (!c->is_active) {
6706 return promise.set_error(Status::Error(400, "Chat is already deactivated"));
6707 }
6708
6709 td_->create_handler<DeleteChatQuery>(std::move(promise))->send(chat_id);
6710 }
6711
delete_channel(ChannelId channel_id,Promise<Unit> && promise)6712 void ContactsManager::delete_channel(ChannelId channel_id, Promise<Unit> &&promise) {
6713 auto c = get_channel(channel_id);
6714 if (c == nullptr) {
6715 return promise.set_error(Status::Error(400, "Chat info not found"));
6716 }
6717 if (!get_channel_status(c).is_creator()) {
6718 return promise.set_error(Status::Error(400, "Not enough rights to delete the chat"));
6719 }
6720
6721 td_->create_handler<DeleteChannelQuery>(std::move(promise))->send(channel_id);
6722 }
6723
delete_dialog(DialogId dialog_id,Promise<Unit> && promise)6724 void ContactsManager::delete_dialog(DialogId dialog_id, Promise<Unit> &&promise) {
6725 if (!td_->messages_manager_->have_dialog_force(dialog_id, "delete_dialog")) {
6726 return promise.set_error(Status::Error(400, "Chat not found"));
6727 }
6728
6729 switch (dialog_id.get_type()) {
6730 case DialogType::User:
6731 return td_->messages_manager_->delete_dialog_history(dialog_id, true, true, std::move(promise));
6732 case DialogType::Chat:
6733 return delete_chat(dialog_id.get_chat_id(), std::move(promise));
6734 case DialogType::Channel:
6735 return delete_channel(dialog_id.get_channel_id(), std::move(promise));
6736 case DialogType::SecretChat:
6737 send_closure(td_->secret_chats_manager_, &SecretChatsManager::cancel_chat, dialog_id.get_secret_chat_id(), true,
6738 std::move(promise));
6739 return;
6740 default:
6741 UNREACHABLE();
6742 }
6743 }
6744
add_chat_participant(ChatId chat_id,UserId user_id,int32 forward_limit,Promise<Unit> && promise)6745 void ContactsManager::add_chat_participant(ChatId chat_id, UserId user_id, int32 forward_limit,
6746 Promise<Unit> &&promise) {
6747 const Chat *c = get_chat(chat_id);
6748 if (c == nullptr) {
6749 return promise.set_error(Status::Error(400, "Chat info not found"));
6750 }
6751 if (!c->is_active) {
6752 return promise.set_error(Status::Error(400, "Chat is deactivated"));
6753 }
6754 if (forward_limit < 0) {
6755 return promise.set_error(Status::Error(400, "Can't forward negative number of messages"));
6756 }
6757 if (user_id != get_my_id()) {
6758 if (!get_chat_permissions(c).can_invite_users()) {
6759 return promise.set_error(Status::Error(400, "Not enough rights to invite members to the group chat"));
6760 }
6761 } else if (c->status.is_banned()) {
6762 return promise.set_error(Status::Error(400, "User was kicked from the chat"));
6763 }
6764 // TODO upper bound on forward_limit
6765
6766 auto input_user = get_input_user(user_id);
6767 if (input_user == nullptr) {
6768 return promise.set_error(Status::Error(400, "User not found"));
6769 }
6770
6771 // TODO invoke after
6772 td_->create_handler<AddChatUserQuery>(std::move(promise))->send(chat_id, std::move(input_user), forward_limit);
6773 }
6774
add_channel_participant(ChannelId channel_id,UserId user_id,const DialogParticipantStatus & old_status,Promise<Unit> && promise)6775 void ContactsManager::add_channel_participant(ChannelId channel_id, UserId user_id,
6776 const DialogParticipantStatus &old_status, Promise<Unit> &&promise) {
6777 if (td_->auth_manager_->is_bot()) {
6778 return promise.set_error(Status::Error(400, "Bots can't add new chat members"));
6779 }
6780
6781 const Channel *c = get_channel(channel_id);
6782 if (c == nullptr) {
6783 return promise.set_error(Status::Error(400, "Chat info not found"));
6784 }
6785 auto input_user = get_input_user(user_id);
6786 if (input_user == nullptr) {
6787 return promise.set_error(Status::Error(400, "User not found"));
6788 }
6789
6790 if (user_id == get_my_id()) {
6791 // join the channel
6792 if (get_channel_status(c).is_banned()) {
6793 return promise.set_error(Status::Error(400, "Can't return to kicked from chat"));
6794 }
6795
6796 speculative_add_channel_user(channel_id, user_id, DialogParticipantStatus::Member(), c->status);
6797 td_->create_handler<JoinChannelQuery>(std::move(promise))->send(channel_id);
6798 return;
6799 }
6800
6801 if (!get_channel_permissions(c).can_invite_users()) {
6802 return promise.set_error(Status::Error(400, "Not enough rights to invite members to the supergroup chat"));
6803 }
6804
6805 speculative_add_channel_user(channel_id, user_id, DialogParticipantStatus::Member(), old_status);
6806 vector<tl_object_ptr<telegram_api::InputUser>> input_users;
6807 input_users.push_back(std::move(input_user));
6808 td_->create_handler<InviteToChannelQuery>(std::move(promise))->send(channel_id, std::move(input_users));
6809 }
6810
add_channel_participants(ChannelId channel_id,const vector<UserId> & user_ids,Promise<Unit> && promise)6811 void ContactsManager::add_channel_participants(ChannelId channel_id, const vector<UserId> &user_ids,
6812 Promise<Unit> &&promise) {
6813 if (td_->auth_manager_->is_bot()) {
6814 return promise.set_error(Status::Error(400, "Bots can't add new chat members"));
6815 }
6816
6817 const Channel *c = get_channel(channel_id);
6818 if (c == nullptr) {
6819 return promise.set_error(Status::Error(400, "Chat info not found"));
6820 }
6821
6822 if (!get_channel_permissions(c).can_invite_users()) {
6823 return promise.set_error(Status::Error(400, "Not enough rights to invite members to the supergroup chat"));
6824 }
6825
6826 vector<tl_object_ptr<telegram_api::InputUser>> input_users;
6827 for (auto user_id : user_ids) {
6828 auto input_user = get_input_user(user_id);
6829 if (input_user == nullptr) {
6830 return promise.set_error(Status::Error(400, "User not found"));
6831 }
6832
6833 if (user_id == get_my_id()) {
6834 // can't invite self
6835 continue;
6836 }
6837 input_users.push_back(std::move(input_user));
6838 }
6839
6840 if (input_users.empty()) {
6841 return promise.set_value(Unit());
6842 }
6843
6844 td_->create_handler<InviteToChannelQuery>(std::move(promise))->send(channel_id, std::move(input_users));
6845 }
6846
set_channel_participant_status(ChannelId channel_id,DialogId participant_dialog_id,DialogParticipantStatus status,Promise<Unit> && promise)6847 void ContactsManager::set_channel_participant_status(ChannelId channel_id, DialogId participant_dialog_id,
6848 DialogParticipantStatus status, Promise<Unit> &&promise) {
6849 auto c = get_channel(channel_id);
6850 if (c == nullptr) {
6851 return promise.set_error(Status::Error(400, "Chat info not found"));
6852 }
6853
6854 if (participant_dialog_id == DialogId(get_my_id())) {
6855 // fast path is needed, because get_channel_status may return Creator, while GetChannelParticipantQuery returning Left
6856 return set_channel_participant_status_impl(channel_id, participant_dialog_id, std::move(status),
6857 get_channel_status(c), std::move(promise));
6858 }
6859 if (participant_dialog_id.get_type() != DialogType::User) {
6860 if (status.is_administrator() || status.is_member() || status.is_restricted()) {
6861 return promise.set_error(Status::Error(400, "Other chats can be only banned or unbanned"));
6862 }
6863 // always pretend that old_status is different
6864 return restrict_channel_participant(
6865 channel_id, participant_dialog_id, std::move(status),
6866 status.is_banned() ? DialogParticipantStatus::Left() : DialogParticipantStatus::Banned(0), std::move(promise));
6867 }
6868
6869 auto input_peer = td_->messages_manager_->get_input_peer(participant_dialog_id, AccessRights::Read);
6870 if (input_peer == nullptr) {
6871 return promise.set_error(Status::Error(400, "Member not found"));
6872 }
6873
6874 auto on_result_promise =
6875 PromiseCreator::lambda([actor_id = actor_id(this), channel_id, participant_dialog_id, status,
6876 promise = std::move(promise)](Result<DialogParticipant> r_dialog_participant) mutable {
6877 // ResultHandlers are cleared before managers, so it is safe to capture this
6878 if (r_dialog_participant.is_error()) {
6879 return promise.set_error(r_dialog_participant.move_as_error());
6880 }
6881
6882 send_closure(actor_id, &ContactsManager::set_channel_participant_status_impl, channel_id, participant_dialog_id,
6883 std::move(status), r_dialog_participant.ok().status_, std::move(promise));
6884 });
6885
6886 td_->create_handler<GetChannelParticipantQuery>(std::move(on_result_promise))
6887 ->send(channel_id, participant_dialog_id, std::move(input_peer));
6888 }
6889
set_channel_participant_status_impl(ChannelId channel_id,DialogId participant_dialog_id,DialogParticipantStatus status,DialogParticipantStatus old_status,Promise<Unit> && promise)6890 void ContactsManager::set_channel_participant_status_impl(ChannelId channel_id, DialogId participant_dialog_id,
6891 DialogParticipantStatus status,
6892 DialogParticipantStatus old_status, Promise<Unit> &&promise) {
6893 if (old_status == status && !old_status.is_creator()) {
6894 return promise.set_value(Unit());
6895 }
6896
6897 LOG(INFO) << "Change status of " << participant_dialog_id << " in " << channel_id << " from " << old_status << " to "
6898 << status;
6899 bool need_add = false;
6900 bool need_promote = false;
6901 bool need_restrict = false;
6902 if (status.is_creator() || old_status.is_creator()) {
6903 if (!old_status.is_creator()) {
6904 return promise.set_error(Status::Error(400, "Can't add another owner to the chat"));
6905 }
6906 if (!status.is_creator()) {
6907 return promise.set_error(Status::Error(400, "Can't remove chat owner"));
6908 }
6909 if (participant_dialog_id != DialogId(get_my_id())) {
6910 return promise.set_error(Status::Error(400, "Not enough rights to edit chat owner rights"));
6911 }
6912 if (status.is_member() == old_status.is_member()) {
6913 // change rank and is_anonymous
6914 auto input_user = get_input_user(get_my_id());
6915 CHECK(input_user != nullptr);
6916 td_->create_handler<EditChannelAdminQuery>(std::move(promise))->send(channel_id, std::move(input_user), status);
6917 return;
6918 }
6919 if (status.is_member()) {
6920 // creator not member -> creator member
6921 need_add = true;
6922 } else {
6923 // creator member -> creator not member
6924 need_restrict = true;
6925 }
6926 } else if (status.is_administrator()) {
6927 need_promote = true;
6928 } else if (!status.is_member() || status.is_restricted()) {
6929 if (status.is_member() && !old_status.is_member()) {
6930 // TODO there is no way in server API to invite someone and change restrictions
6931 // we need to first add user and change restrictions again after that
6932 // but if restrictions aren't changed, then adding is enough
6933 auto copy_old_status = old_status;
6934 copy_old_status.set_is_member(true);
6935 if (copy_old_status == status) {
6936 need_add = true;
6937 } else {
6938 need_restrict = true;
6939 }
6940 } else {
6941 need_restrict = true;
6942 }
6943 } else {
6944 // regular member
6945 if (old_status.is_administrator()) {
6946 need_promote = true;
6947 } else if (old_status.is_restricted() || old_status.is_banned()) {
6948 need_restrict = true;
6949 } else {
6950 CHECK(!old_status.is_member());
6951 need_add = true;
6952 }
6953 }
6954
6955 if (need_promote) {
6956 if (participant_dialog_id.get_type() != DialogType::User) {
6957 return promise.set_error(Status::Error(400, "Can't promote chats to chat administrators"));
6958 }
6959 return promote_channel_participant(channel_id, participant_dialog_id.get_user_id(), status, old_status,
6960 std::move(promise));
6961 } else if (need_restrict) {
6962 return restrict_channel_participant(channel_id, participant_dialog_id, std::move(status), std::move(old_status),
6963 std::move(promise));
6964 } else {
6965 CHECK(need_add);
6966 if (participant_dialog_id.get_type() != DialogType::User) {
6967 return promise.set_error(Status::Error(400, "Can't add chats as chat members"));
6968 }
6969 return add_channel_participant(channel_id, participant_dialog_id.get_user_id(), old_status, std::move(promise));
6970 }
6971 }
6972
promote_channel_participant(ChannelId channel_id,UserId user_id,const DialogParticipantStatus & status,const DialogParticipantStatus & old_status,Promise<Unit> && promise)6973 void ContactsManager::promote_channel_participant(ChannelId channel_id, UserId user_id,
6974 const DialogParticipantStatus &status,
6975 const DialogParticipantStatus &old_status, Promise<Unit> &&promise) {
6976 LOG(INFO) << "Promote " << user_id << " in " << channel_id << " from " << old_status << " to " << status;
6977 const Channel *c = get_channel(channel_id);
6978 CHECK(c != nullptr);
6979
6980 if (user_id == get_my_id()) {
6981 if (status.is_administrator()) {
6982 return promise.set_error(Status::Error(400, "Can't promote self"));
6983 }
6984 CHECK(status.is_member());
6985 // allow to demote self. TODO is it allowed server-side?
6986 } else {
6987 if (!get_channel_permissions(c).can_promote_members()) {
6988 return promise.set_error(Status::Error(400, "Not enough rights"));
6989 }
6990
6991 CHECK(!old_status.is_creator());
6992 CHECK(!status.is_creator());
6993 }
6994
6995 auto input_user = get_input_user(user_id);
6996 if (input_user == nullptr) {
6997 return promise.set_error(Status::Error(400, "User not found"));
6998 }
6999
7000 speculative_add_channel_user(channel_id, user_id, status, old_status);
7001 td_->create_handler<EditChannelAdminQuery>(std::move(promise))->send(channel_id, std::move(input_user), status);
7002 }
7003
set_chat_participant_status(ChatId chat_id,UserId user_id,DialogParticipantStatus status,Promise<Unit> && promise)7004 void ContactsManager::set_chat_participant_status(ChatId chat_id, UserId user_id, DialogParticipantStatus status,
7005 Promise<Unit> &&promise) {
7006 if (!status.is_member()) {
7007 return delete_chat_participant(chat_id, user_id, false, std::move(promise));
7008 }
7009 if (status.is_creator()) {
7010 return promise.set_error(Status::Error(400, "Can't change owner in basic group chats"));
7011 }
7012 if (status.is_restricted()) {
7013 return promise.set_error(Status::Error(400, "Can't restrict users in basic group chats"));
7014 }
7015
7016 auto c = get_chat(chat_id);
7017 if (c == nullptr) {
7018 return promise.set_error(Status::Error(400, "Chat info not found"));
7019 }
7020 if (!c->is_active) {
7021 return promise.set_error(Status::Error(400, "Chat is deactivated"));
7022 }
7023
7024 auto chat_full = get_chat_full(chat_id);
7025 if (chat_full == nullptr) {
7026 auto load_chat_full_promise =
7027 PromiseCreator::lambda([actor_id = actor_id(this), chat_id, user_id, status = std::move(status),
7028 promise = std::move(promise)](Result<Unit> &&result) mutable {
7029 if (result.is_error()) {
7030 promise.set_error(result.move_as_error());
7031 } else {
7032 send_closure(actor_id, &ContactsManager::set_chat_participant_status, chat_id, user_id, status,
7033 std::move(promise));
7034 }
7035 });
7036 return load_chat_full(chat_id, false, std::move(load_chat_full_promise), "set_chat_participant_status");
7037 }
7038
7039 auto participant = get_chat_full_participant(chat_full, DialogId(user_id));
7040 if (participant == nullptr && !status.is_administrator()) {
7041 // the user isn't a member, but needs to be added
7042 return add_chat_participant(chat_id, user_id, 0, std::move(promise));
7043 }
7044
7045 if (!get_chat_permissions(c).can_promote_members()) {
7046 return promise.set_error(Status::Error(400, "Need owner rights in the group chat"));
7047 }
7048
7049 if (user_id == get_my_id()) {
7050 return promise.set_error(Status::Error(400, "Can't promote or demote self"));
7051 }
7052
7053 if (participant == nullptr) {
7054 // the user must be added first
7055 CHECK(status.is_administrator());
7056 auto add_chat_participant_promise = PromiseCreator::lambda(
7057 [actor_id = actor_id(this), chat_id, user_id, promise = std::move(promise)](Result<Unit> &&result) mutable {
7058 if (result.is_error()) {
7059 promise.set_error(result.move_as_error());
7060 } else {
7061 send_closure(actor_id, &ContactsManager::send_edit_chat_admin_query, chat_id, user_id, true,
7062 std::move(promise));
7063 }
7064 });
7065 return add_chat_participant(chat_id, user_id, 0, std::move(add_chat_participant_promise));
7066 }
7067
7068 send_edit_chat_admin_query(chat_id, user_id, status.is_administrator(), std::move(promise));
7069 }
7070
send_edit_chat_admin_query(ChatId chat_id,UserId user_id,bool is_administrator,Promise<Unit> && promise)7071 void ContactsManager::send_edit_chat_admin_query(ChatId chat_id, UserId user_id, bool is_administrator,
7072 Promise<Unit> &&promise) {
7073 auto input_user = get_input_user(user_id);
7074 if (input_user == nullptr) {
7075 return promise.set_error(Status::Error(400, "User not found"));
7076 }
7077
7078 td_->create_handler<EditChatAdminQuery>(std::move(promise))->send(chat_id, std::move(input_user), is_administrator);
7079 }
7080
can_transfer_ownership(Promise<CanTransferOwnershipResult> && promise)7081 void ContactsManager::can_transfer_ownership(Promise<CanTransferOwnershipResult> &&promise) {
7082 auto request_promise = PromiseCreator::lambda([promise = std::move(promise)](Result<Unit> r_result) mutable {
7083 CHECK(r_result.is_error());
7084
7085 auto error = r_result.move_as_error();
7086 CanTransferOwnershipResult result;
7087 if (error.message() == "PASSWORD_HASH_INVALID") {
7088 return promise.set_value(std::move(result));
7089 }
7090 if (error.message() == "PASSWORD_MISSING") {
7091 result.type = CanTransferOwnershipResult::Type::PasswordNeeded;
7092 return promise.set_value(std::move(result));
7093 }
7094 if (begins_with(error.message(), "PASSWORD_TOO_FRESH_")) {
7095 result.type = CanTransferOwnershipResult::Type::PasswordTooFresh;
7096 result.retry_after = to_integer<int32>(error.message().substr(Slice("PASSWORD_TOO_FRESH_").size()));
7097 if (result.retry_after < 0) {
7098 result.retry_after = 0;
7099 }
7100 return promise.set_value(std::move(result));
7101 }
7102 if (begins_with(error.message(), "SESSION_TOO_FRESH_")) {
7103 result.type = CanTransferOwnershipResult::Type::SessionTooFresh;
7104 result.retry_after = to_integer<int32>(error.message().substr(Slice("SESSION_TOO_FRESH_").size()));
7105 if (result.retry_after < 0) {
7106 result.retry_after = 0;
7107 }
7108 return promise.set_value(std::move(result));
7109 }
7110 promise.set_error(std::move(error));
7111 });
7112
7113 td_->create_handler<CanEditChannelCreatorQuery>(std::move(request_promise))->send();
7114 }
7115
get_can_transfer_ownership_result_object(CanTransferOwnershipResult result)7116 td_api::object_ptr<td_api::CanTransferOwnershipResult> ContactsManager::get_can_transfer_ownership_result_object(
7117 CanTransferOwnershipResult result) {
7118 switch (result.type) {
7119 case CanTransferOwnershipResult::Type::Ok:
7120 return td_api::make_object<td_api::canTransferOwnershipResultOk>();
7121 case CanTransferOwnershipResult::Type::PasswordNeeded:
7122 return td_api::make_object<td_api::canTransferOwnershipResultPasswordNeeded>();
7123 case CanTransferOwnershipResult::Type::PasswordTooFresh:
7124 return td_api::make_object<td_api::canTransferOwnershipResultPasswordTooFresh>(result.retry_after);
7125 case CanTransferOwnershipResult::Type::SessionTooFresh:
7126 return td_api::make_object<td_api::canTransferOwnershipResultSessionTooFresh>(result.retry_after);
7127 default:
7128 UNREACHABLE();
7129 return nullptr;
7130 }
7131 }
7132
transfer_dialog_ownership(DialogId dialog_id,UserId user_id,const string & password,Promise<Unit> && promise)7133 void ContactsManager::transfer_dialog_ownership(DialogId dialog_id, UserId user_id, const string &password,
7134 Promise<Unit> &&promise) {
7135 if (!td_->messages_manager_->have_dialog_force(dialog_id, "transfer_dialog_ownership")) {
7136 return promise.set_error(Status::Error(400, "Chat not found"));
7137 }
7138 if (!have_user_force(user_id)) {
7139 return promise.set_error(Status::Error(400, "User not found"));
7140 }
7141 if (is_user_bot(user_id)) {
7142 return promise.set_error(Status::Error(400, "User is a bot"));
7143 }
7144 if (is_user_deleted(user_id)) {
7145 return promise.set_error(Status::Error(400, "User is deleted"));
7146 }
7147 if (password.empty()) {
7148 return promise.set_error(Status::Error(400, "PASSWORD_HASH_INVALID"));
7149 }
7150
7151 switch (dialog_id.get_type()) {
7152 case DialogType::User:
7153 case DialogType::Chat:
7154 case DialogType::SecretChat:
7155 return promise.set_error(Status::Error(400, "Can't transfer chat ownership"));
7156 case DialogType::Channel:
7157 send_closure(
7158 td_->password_manager_, &PasswordManager::get_input_check_password_srp, password,
7159 PromiseCreator::lambda([actor_id = actor_id(this), channel_id = dialog_id.get_channel_id(), user_id,
7160 promise = std::move(promise)](
7161 Result<tl_object_ptr<telegram_api::InputCheckPasswordSRP>> result) mutable {
7162 if (result.is_error()) {
7163 return promise.set_error(result.move_as_error());
7164 }
7165 send_closure(actor_id, &ContactsManager::transfer_channel_ownership, channel_id, user_id,
7166 result.move_as_ok(), std::move(promise));
7167 }));
7168 break;
7169 case DialogType::None:
7170 default:
7171 UNREACHABLE();
7172 }
7173 }
7174
transfer_channel_ownership(ChannelId channel_id,UserId user_id,tl_object_ptr<telegram_api::InputCheckPasswordSRP> input_check_password,Promise<Unit> && promise)7175 void ContactsManager::transfer_channel_ownership(
7176 ChannelId channel_id, UserId user_id, tl_object_ptr<telegram_api::InputCheckPasswordSRP> input_check_password,
7177 Promise<Unit> &&promise) {
7178 TRY_STATUS_PROMISE(promise, G()->close_status());
7179
7180 td_->create_handler<EditChannelCreatorQuery>(std::move(promise))
7181 ->send(channel_id, user_id, std::move(input_check_password));
7182 }
7183
can_manage_dialog_invite_links(DialogId dialog_id,bool creator_only)7184 Status ContactsManager::can_manage_dialog_invite_links(DialogId dialog_id, bool creator_only) {
7185 if (!td_->messages_manager_->have_dialog_force(dialog_id, "can_manage_dialog_invite_links")) {
7186 return Status::Error(400, "Chat not found");
7187 }
7188
7189 switch (dialog_id.get_type()) {
7190 case DialogType::User:
7191 return Status::Error(400, "Can't invite members to a private chat");
7192 case DialogType::Chat: {
7193 const Chat *c = get_chat(dialog_id.get_chat_id());
7194 if (c == nullptr) {
7195 return Status::Error(400, "Chat info not found");
7196 }
7197 if (!c->is_active) {
7198 return Status::Error(400, "Chat is deactivated");
7199 }
7200 bool have_rights = creator_only ? c->status.is_creator() : c->status.can_manage_invite_links();
7201 if (!have_rights) {
7202 return Status::Error(400, "Not enough rights to manage chat invite link");
7203 }
7204 break;
7205 }
7206 case DialogType::Channel: {
7207 const Channel *c = get_channel(dialog_id.get_channel_id());
7208 if (c == nullptr) {
7209 return Status::Error(400, "Chat info not found");
7210 }
7211 bool have_rights = creator_only ? c->status.is_creator() : c->status.can_manage_invite_links();
7212 if (!have_rights) {
7213 return Status::Error(400, "Not enough rights to manage chat invite link");
7214 }
7215 break;
7216 }
7217 case DialogType::SecretChat:
7218 return Status::Error(400, "Can't invite members to a secret chat");
7219 case DialogType::None:
7220 default:
7221 UNREACHABLE();
7222 }
7223 return Status::OK();
7224 }
7225
export_dialog_invite_link(DialogId dialog_id,string title,int32 expire_date,int32 usage_limit,bool creates_join_request,bool is_permanent,Promise<td_api::object_ptr<td_api::chatInviteLink>> && promise)7226 void ContactsManager::export_dialog_invite_link(DialogId dialog_id, string title, int32 expire_date, int32 usage_limit,
7227 bool creates_join_request, bool is_permanent,
7228 Promise<td_api::object_ptr<td_api::chatInviteLink>> &&promise) {
7229 get_me(PromiseCreator::lambda([actor_id = actor_id(this), dialog_id, title = std::move(title), expire_date,
7230 usage_limit, creates_join_request, is_permanent,
7231 promise = std::move(promise)](Result<Unit> &&result) mutable {
7232 if (result.is_error()) {
7233 promise.set_error(result.move_as_error());
7234 } else {
7235 send_closure(actor_id, &ContactsManager::export_dialog_invite_link_impl, dialog_id, std::move(title), expire_date,
7236 usage_limit, creates_join_request, is_permanent, std::move(promise));
7237 }
7238 }));
7239 }
7240
export_dialog_invite_link_impl(DialogId dialog_id,string title,int32 expire_date,int32 usage_limit,bool creates_join_request,bool is_permanent,Promise<td_api::object_ptr<td_api::chatInviteLink>> && promise)7241 void ContactsManager::export_dialog_invite_link_impl(DialogId dialog_id, string title, int32 expire_date,
7242 int32 usage_limit, bool creates_join_request, bool is_permanent,
7243 Promise<td_api::object_ptr<td_api::chatInviteLink>> &&promise) {
7244 TRY_STATUS_PROMISE(promise, G()->close_status());
7245 TRY_STATUS_PROMISE(promise, can_manage_dialog_invite_links(dialog_id));
7246 if (creates_join_request && usage_limit > 0) {
7247 return promise.set_error(
7248 Status::Error(400, "Member limit can't be specified for links requiring administrator approval"));
7249 }
7250
7251 auto new_title = clean_name(std::move(title), MAX_INVITE_LINK_TITLE_LENGTH);
7252 td_->create_handler<ExportChatInviteQuery>(std::move(promise))
7253 ->send(dialog_id, new_title, expire_date, usage_limit, creates_join_request, is_permanent);
7254 }
7255
edit_dialog_invite_link(DialogId dialog_id,const string & invite_link,string title,int32 expire_date,int32 usage_limit,bool creates_join_request,Promise<td_api::object_ptr<td_api::chatInviteLink>> && promise)7256 void ContactsManager::edit_dialog_invite_link(DialogId dialog_id, const string &invite_link, string title,
7257 int32 expire_date, int32 usage_limit, bool creates_join_request,
7258 Promise<td_api::object_ptr<td_api::chatInviteLink>> &&promise) {
7259 TRY_STATUS_PROMISE(promise, can_manage_dialog_invite_links(dialog_id));
7260 if (creates_join_request && usage_limit > 0) {
7261 return promise.set_error(
7262 Status::Error(400, "Member limit can't be specified for links requiring administrator approval"));
7263 }
7264
7265 if (invite_link.empty()) {
7266 return promise.set_error(Status::Error(400, "Invite link must be non-empty"));
7267 }
7268
7269 auto new_title = clean_name(std::move(title), MAX_INVITE_LINK_TITLE_LENGTH);
7270 td_->create_handler<EditChatInviteLinkQuery>(std::move(promise))
7271 ->send(dialog_id, invite_link, new_title, expire_date, usage_limit, creates_join_request);
7272 }
7273
get_dialog_invite_link(DialogId dialog_id,const string & invite_link,Promise<td_api::object_ptr<td_api::chatInviteLink>> && promise)7274 void ContactsManager::get_dialog_invite_link(DialogId dialog_id, const string &invite_link,
7275 Promise<td_api::object_ptr<td_api::chatInviteLink>> &&promise) {
7276 TRY_STATUS_PROMISE(promise, can_manage_dialog_invite_links(dialog_id, false));
7277
7278 if (invite_link.empty()) {
7279 return promise.set_error(Status::Error(400, "Invite link must be non-empty"));
7280 }
7281
7282 td_->create_handler<GetExportedChatInviteQuery>(std::move(promise))->send(dialog_id, invite_link);
7283 }
7284
get_dialog_invite_link_counts(DialogId dialog_id,Promise<td_api::object_ptr<td_api::chatInviteLinkCounts>> && promise)7285 void ContactsManager::get_dialog_invite_link_counts(
7286 DialogId dialog_id, Promise<td_api::object_ptr<td_api::chatInviteLinkCounts>> &&promise) {
7287 TRY_STATUS_PROMISE(promise, can_manage_dialog_invite_links(dialog_id, true));
7288
7289 td_->create_handler<GetChatAdminWithInvitesQuery>(std::move(promise))->send(dialog_id);
7290 }
7291
get_dialog_invite_links(DialogId dialog_id,UserId creator_user_id,bool is_revoked,int32 offset_date,const string & offset_invite_link,int32 limit,Promise<td_api::object_ptr<td_api::chatInviteLinks>> && promise)7292 void ContactsManager::get_dialog_invite_links(DialogId dialog_id, UserId creator_user_id, bool is_revoked,
7293 int32 offset_date, const string &offset_invite_link, int32 limit,
7294 Promise<td_api::object_ptr<td_api::chatInviteLinks>> &&promise) {
7295 TRY_STATUS_PROMISE(promise, can_manage_dialog_invite_links(dialog_id, creator_user_id != get_my_id()));
7296
7297 if (!have_input_user(creator_user_id)) {
7298 return promise.set_error(Status::Error(400, "Administrator user not found"));
7299 }
7300
7301 if (limit <= 0) {
7302 return promise.set_error(Status::Error(400, "Parameter limit must be positive"));
7303 }
7304
7305 td_->create_handler<GetExportedChatInvitesQuery>(std::move(promise))
7306 ->send(dialog_id, creator_user_id, is_revoked, offset_date, offset_invite_link, limit);
7307 }
7308
get_dialog_invite_link_users(DialogId dialog_id,const string & invite_link,td_api::object_ptr<td_api::chatInviteLinkMember> offset_member,int32 limit,Promise<td_api::object_ptr<td_api::chatInviteLinkMembers>> && promise)7309 void ContactsManager::get_dialog_invite_link_users(
7310 DialogId dialog_id, const string &invite_link, td_api::object_ptr<td_api::chatInviteLinkMember> offset_member,
7311 int32 limit, Promise<td_api::object_ptr<td_api::chatInviteLinkMembers>> &&promise) {
7312 TRY_STATUS_PROMISE(promise, can_manage_dialog_invite_links(dialog_id));
7313
7314 if (limit <= 0) {
7315 return promise.set_error(Status::Error(400, "Parameter limit must be positive"));
7316 }
7317
7318 if (invite_link.empty()) {
7319 return promise.set_error(Status::Error(400, "Invite link must be non-empty"));
7320 }
7321
7322 UserId offset_user_id;
7323 int32 offset_date = 0;
7324 if (offset_member != nullptr) {
7325 offset_user_id = UserId(offset_member->user_id_);
7326 offset_date = offset_member->joined_chat_date_;
7327 }
7328
7329 td_->create_handler<GetChatInviteImportersQuery>(std::move(promise))
7330 ->send(dialog_id, invite_link, offset_date, offset_user_id, limit);
7331 }
7332
get_dialog_join_requests(DialogId dialog_id,const string & invite_link,const string & query,td_api::object_ptr<td_api::chatJoinRequest> offset_request,int32 limit,Promise<td_api::object_ptr<td_api::chatJoinRequests>> && promise)7333 void ContactsManager::get_dialog_join_requests(DialogId dialog_id, const string &invite_link, const string &query,
7334 td_api::object_ptr<td_api::chatJoinRequest> offset_request, int32 limit,
7335 Promise<td_api::object_ptr<td_api::chatJoinRequests>> &&promise) {
7336 TRY_STATUS_PROMISE(promise, can_manage_dialog_invite_links(dialog_id));
7337
7338 if (limit <= 0) {
7339 return promise.set_error(Status::Error(400, "Parameter limit must be positive"));
7340 }
7341
7342 UserId offset_user_id;
7343 int32 offset_date = 0;
7344 if (offset_request != nullptr) {
7345 offset_user_id = UserId(offset_request->user_id_);
7346 offset_date = offset_request->date_;
7347 }
7348
7349 td_->create_handler<GetChatJoinRequestsQuery>(std::move(promise))
7350 ->send(dialog_id, invite_link, query, offset_date, offset_user_id, limit);
7351 }
7352
process_dialog_join_request(DialogId dialog_id,UserId user_id,bool approve,Promise<Unit> && promise)7353 void ContactsManager::process_dialog_join_request(DialogId dialog_id, UserId user_id, bool approve,
7354 Promise<Unit> &&promise) {
7355 TRY_STATUS_PROMISE(promise, can_manage_dialog_invite_links(dialog_id));
7356 td_->create_handler<HideChatJoinRequestQuery>(std::move(promise))->send(dialog_id, user_id, approve);
7357 }
7358
process_dialog_join_requests(DialogId dialog_id,const string & invite_link,bool approve,Promise<Unit> && promise)7359 void ContactsManager::process_dialog_join_requests(DialogId dialog_id, const string &invite_link, bool approve,
7360 Promise<Unit> &&promise) {
7361 TRY_STATUS_PROMISE(promise, can_manage_dialog_invite_links(dialog_id));
7362 td_->create_handler<HideAllChatJoinRequestsQuery>(std::move(promise))->send(dialog_id, invite_link, approve);
7363 }
7364
revoke_dialog_invite_link(DialogId dialog_id,const string & invite_link,Promise<td_api::object_ptr<td_api::chatInviteLinks>> && promise)7365 void ContactsManager::revoke_dialog_invite_link(DialogId dialog_id, const string &invite_link,
7366 Promise<td_api::object_ptr<td_api::chatInviteLinks>> &&promise) {
7367 TRY_STATUS_PROMISE(promise, can_manage_dialog_invite_links(dialog_id));
7368
7369 if (invite_link.empty()) {
7370 return promise.set_error(Status::Error(400, "Invite link must be non-empty"));
7371 }
7372
7373 td_->create_handler<RevokeChatInviteLinkQuery>(std::move(promise))->send(dialog_id, invite_link);
7374 }
7375
delete_revoked_dialog_invite_link(DialogId dialog_id,const string & invite_link,Promise<Unit> && promise)7376 void ContactsManager::delete_revoked_dialog_invite_link(DialogId dialog_id, const string &invite_link,
7377 Promise<Unit> &&promise) {
7378 TRY_STATUS_PROMISE(promise, can_manage_dialog_invite_links(dialog_id));
7379
7380 if (invite_link.empty()) {
7381 return promise.set_error(Status::Error(400, "Invite link must be non-empty"));
7382 }
7383
7384 td_->create_handler<DeleteExportedChatInviteQuery>(std::move(promise))->send(dialog_id, invite_link);
7385 }
7386
delete_all_revoked_dialog_invite_links(DialogId dialog_id,UserId creator_user_id,Promise<Unit> && promise)7387 void ContactsManager::delete_all_revoked_dialog_invite_links(DialogId dialog_id, UserId creator_user_id,
7388 Promise<Unit> &&promise) {
7389 TRY_STATUS_PROMISE(promise, can_manage_dialog_invite_links(dialog_id, creator_user_id != get_my_id()));
7390
7391 if (!have_input_user(creator_user_id)) {
7392 return promise.set_error(Status::Error(400, "Administrator user not found"));
7393 }
7394
7395 td_->create_handler<DeleteRevokedExportedChatInvitesQuery>(std::move(promise))->send(dialog_id, creator_user_id);
7396 }
7397
check_dialog_invite_link(const string & invite_link,Promise<Unit> && promise) const7398 void ContactsManager::check_dialog_invite_link(const string &invite_link, Promise<Unit> &&promise) const {
7399 if (invite_link_infos_.count(invite_link) > 0) {
7400 return promise.set_value(Unit());
7401 }
7402
7403 if (!DialogInviteLink::is_valid_invite_link(invite_link)) {
7404 return promise.set_error(Status::Error(400, "Wrong invite link"));
7405 }
7406
7407 td_->create_handler<CheckChatInviteQuery>(std::move(promise))->send(invite_link);
7408 }
7409
import_dialog_invite_link(const string & invite_link,Promise<DialogId> && promise)7410 void ContactsManager::import_dialog_invite_link(const string &invite_link, Promise<DialogId> &&promise) {
7411 if (!DialogInviteLink::is_valid_invite_link(invite_link)) {
7412 return promise.set_error(Status::Error(400, "Wrong invite link"));
7413 }
7414
7415 td_->create_handler<ImportChatInviteQuery>(std::move(promise))->send(invite_link);
7416 }
7417
delete_chat_participant(ChatId chat_id,UserId user_id,bool revoke_messages,Promise<Unit> && promise)7418 void ContactsManager::delete_chat_participant(ChatId chat_id, UserId user_id, bool revoke_messages,
7419 Promise<Unit> &&promise) {
7420 const Chat *c = get_chat(chat_id);
7421 if (c == nullptr) {
7422 return promise.set_error(Status::Error(400, "Chat info not found"));
7423 }
7424 if (!c->is_active) {
7425 return promise.set_error(Status::Error(400, "Chat is deactivated"));
7426 }
7427 auto my_id = get_my_id();
7428 if (c->status.is_left()) {
7429 if (user_id == my_id) {
7430 if (revoke_messages) {
7431 return td_->messages_manager_->delete_dialog_history(DialogId(chat_id), true, true, std::move(promise));
7432 }
7433 return promise.set_value(Unit());
7434 } else {
7435 return promise.set_error(Status::Error(400, "Not in the chat"));
7436 }
7437 }
7438 if (user_id != my_id) {
7439 auto my_status = get_chat_permissions(c);
7440 if (!my_status.is_creator()) { // creator can delete anyone
7441 auto participant = get_chat_participant(chat_id, user_id);
7442 if (participant != nullptr) { // if have no information about participant, just send request to the server
7443 /*
7444 TODO
7445 if (c->everyone_is_administrator) {
7446 // if all are administrators, only invited by me participants can be deleted
7447 if (participant->inviter_user_id_ != my_id) {
7448 return promise.set_error(Status::Error(400, "Need to be inviter of a user to kick it from a basic group"));
7449 }
7450 } else {
7451 // otherwise, only creator can kick administrators
7452 if (participant->status_.is_administrator()) {
7453 return promise.set_error(
7454 Status::Error(400, "Only the creator of a basic group can kick group administrators"));
7455 }
7456 // regular users can be kicked by administrators and their inviters
7457 if (!my_status.is_administrator() && participant->inviter_user_id_ != my_id) {
7458 return promise.set_error(Status::Error(400, "Need to be inviter of a user to kick it from a basic group"));
7459 }
7460 }
7461 */
7462 }
7463 }
7464 }
7465 auto input_user = get_input_user(user_id);
7466 if (input_user == nullptr) {
7467 return promise.set_error(Status::Error(400, "User not found"));
7468 }
7469
7470 // TODO invoke after
7471 td_->create_handler<DeleteChatUserQuery>(std::move(promise))->send(chat_id, std::move(input_user), revoke_messages);
7472 }
7473
restrict_channel_participant(ChannelId channel_id,DialogId participant_dialog_id,DialogParticipantStatus && status,DialogParticipantStatus && old_status,Promise<Unit> && promise)7474 void ContactsManager::restrict_channel_participant(ChannelId channel_id, DialogId participant_dialog_id,
7475 DialogParticipantStatus &&status,
7476 DialogParticipantStatus &&old_status, Promise<Unit> &&promise) {
7477 TRY_STATUS_PROMISE(promise, G()->close_status());
7478
7479 LOG(INFO) << "Restrict " << participant_dialog_id << " in " << channel_id << " from " << old_status << " to "
7480 << status;
7481 const Channel *c = get_channel(channel_id);
7482 if (c == nullptr) {
7483 return promise.set_error(Status::Error(400, "Chat info not found"));
7484 }
7485 if (!c->status.is_member() && !c->status.is_creator()) {
7486 if (participant_dialog_id == DialogId(get_my_id())) {
7487 if (status.is_member()) {
7488 return promise.set_error(Status::Error(400, "Can't unrestrict self"));
7489 }
7490 return promise.set_value(Unit());
7491 } else {
7492 return promise.set_error(Status::Error(400, "Not in the chat"));
7493 }
7494 }
7495 auto input_peer = td_->messages_manager_->get_input_peer(participant_dialog_id, AccessRights::Know);
7496 if (input_peer == nullptr) {
7497 return promise.set_error(Status::Error(400, "Member not found"));
7498 }
7499
7500 if (participant_dialog_id == DialogId(get_my_id())) {
7501 if (status.is_restricted() || status.is_banned()) {
7502 return promise.set_error(Status::Error(400, "Can't restrict self"));
7503 }
7504 if (status.is_member()) {
7505 return promise.set_error(Status::Error(400, "Can't unrestrict self"));
7506 }
7507
7508 // leave the channel
7509 speculative_add_channel_user(channel_id, participant_dialog_id.get_user_id(), status, c->status);
7510 td_->create_handler<LeaveChannelQuery>(std::move(promise))->send(channel_id);
7511 return;
7512 }
7513
7514 switch (participant_dialog_id.get_type()) {
7515 case DialogType::User:
7516 // ok;
7517 break;
7518 case DialogType::Channel:
7519 if (status.is_administrator() || status.is_member() || status.is_restricted()) {
7520 return promise.set_error(Status::Error(400, "Other chats can be only banned or unbanned"));
7521 }
7522 break;
7523 default:
7524 return promise.set_error(Status::Error(400, "Can't restrict the chat"));
7525 }
7526
7527 CHECK(!old_status.is_creator());
7528 CHECK(!status.is_creator());
7529
7530 if (!get_channel_permissions(c).can_restrict_members()) {
7531 return promise.set_error(Status::Error(400, "Not enough rights to restrict/unrestrict chat member"));
7532 }
7533
7534 if (old_status.is_member() && !status.is_member() && !status.is_banned()) {
7535 // we can't make participant Left without kicking it first
7536 auto on_result_promise = PromiseCreator::lambda([actor_id = actor_id(this), channel_id, participant_dialog_id,
7537 status = std::move(status),
7538 promise = std::move(promise)](Result<> result) mutable {
7539 if (result.is_error()) {
7540 return promise.set_error(result.move_as_error());
7541 }
7542
7543 create_actor<SleepActor>(
7544 "RestrictChannelParticipantSleepActor", 1.0,
7545 PromiseCreator::lambda([actor_id, channel_id, participant_dialog_id, status = std::move(status),
7546 promise = std::move(promise)](Result<> result) mutable {
7547 if (result.is_error()) {
7548 return promise.set_error(result.move_as_error());
7549 }
7550
7551 send_closure(actor_id, &ContactsManager::restrict_channel_participant, channel_id, participant_dialog_id,
7552 std::move(status), DialogParticipantStatus::Banned(0), std::move(promise));
7553 }))
7554 .release();
7555 });
7556
7557 promise = std::move(on_result_promise);
7558 status = DialogParticipantStatus::Banned(G()->unix_time() + 60);
7559 }
7560
7561 if (participant_dialog_id.get_type() == DialogType::User) {
7562 speculative_add_channel_user(channel_id, participant_dialog_id.get_user_id(), status, old_status);
7563 }
7564 td_->create_handler<EditChannelBannedQuery>(std::move(promise))->send(channel_id, std::move(input_peer), status);
7565 }
7566
migrate_chat_to_megagroup(ChatId chat_id,Promise<Unit> & promise)7567 ChannelId ContactsManager::migrate_chat_to_megagroup(ChatId chat_id, Promise<Unit> &promise) {
7568 auto c = get_chat(chat_id);
7569 if (c == nullptr) {
7570 promise.set_error(Status::Error(400, "Chat info not found"));
7571 return ChannelId();
7572 }
7573
7574 if (!c->status.is_creator()) {
7575 promise.set_error(Status::Error(400, "Need creator rights in the chat"));
7576 return ChannelId();
7577 }
7578
7579 if (c->migrated_to_channel_id.is_valid()) {
7580 return c->migrated_to_channel_id;
7581 }
7582
7583 td_->create_handler<MigrateChatQuery>(std::move(promise))->send(chat_id);
7584 return ChannelId();
7585 }
7586
get_channel_ids(vector<tl_object_ptr<telegram_api::Chat>> && chats,const char * source)7587 vector<ChannelId> ContactsManager::get_channel_ids(vector<tl_object_ptr<telegram_api::Chat>> &&chats,
7588 const char *source) {
7589 vector<ChannelId> channel_ids;
7590 for (auto &chat : chats) {
7591 auto channel_id = get_channel_id(chat);
7592 if (!channel_id.is_valid()) {
7593 LOG(ERROR) << "Receive invalid " << channel_id << " from " << source << " in " << to_string(chat);
7594 continue;
7595 }
7596 on_get_chat(std::move(chat), source);
7597 if (have_channel(channel_id)) {
7598 channel_ids.push_back(channel_id);
7599 }
7600 }
7601 return channel_ids;
7602 }
7603
get_dialog_ids(vector<tl_object_ptr<telegram_api::Chat>> && chats,const char * source)7604 vector<DialogId> ContactsManager::get_dialog_ids(vector<tl_object_ptr<telegram_api::Chat>> &&chats,
7605 const char *source) {
7606 vector<DialogId> dialog_ids;
7607 for (auto &chat : chats) {
7608 auto channel_id = get_channel_id(chat);
7609 if (!channel_id.is_valid()) {
7610 auto chat_id = get_chat_id(chat);
7611 if (!chat_id.is_valid()) {
7612 LOG(ERROR) << "Receive invalid chat from " << source << " in " << to_string(chat);
7613 } else {
7614 dialog_ids.push_back(DialogId(chat_id));
7615 }
7616 } else {
7617 dialog_ids.push_back(DialogId(channel_id));
7618 }
7619 on_get_chat(std::move(chat), source);
7620 }
7621 return dialog_ids;
7622 }
7623
return_created_public_dialogs(Promise<td_api::object_ptr<td_api::chats>> && promise,const vector<ChannelId> & channel_ids)7624 void ContactsManager::return_created_public_dialogs(Promise<td_api::object_ptr<td_api::chats>> &&promise,
7625 const vector<ChannelId> &channel_ids) {
7626 if (!promise) {
7627 return;
7628 }
7629
7630 auto total_count = narrow_cast<int32>(channel_ids.size());
7631 promise.set_value(td_api::make_object<td_api::chats>(
7632 total_count, transform(channel_ids, [](ChannelId channel_id) { return DialogId(channel_id).get(); })));
7633 }
7634
get_created_public_dialogs(PublicDialogType type,Promise<td_api::object_ptr<td_api::chats>> && promise,bool from_binlog)7635 void ContactsManager::get_created_public_dialogs(PublicDialogType type,
7636 Promise<td_api::object_ptr<td_api::chats>> &&promise,
7637 bool from_binlog) {
7638 auto index = static_cast<int32>(type);
7639 if (created_public_channels_inited_[index]) {
7640 return return_created_public_dialogs(std::move(promise), created_public_channels_[index]);
7641 }
7642
7643 if (get_created_public_channels_queries_[index].empty() && G()->parameters().use_chat_info_db) {
7644 auto pmc_key = PSTRING() << "public_channels" << index;
7645 auto str = G()->td_db()->get_binlog_pmc()->get(pmc_key);
7646 if (!str.empty()) {
7647 auto r_channel_ids = transform(full_split(Slice(str), ','), [](Slice str) -> Result<ChannelId> {
7648 TRY_RESULT(channel_id_int, to_integer_safe<int64>(str));
7649 ChannelId channel_id(channel_id_int);
7650 if (!channel_id.is_valid()) {
7651 return Status::Error("Have invalid channel ID");
7652 }
7653 return channel_id;
7654 });
7655 if (std::any_of(r_channel_ids.begin(), r_channel_ids.end(),
7656 [](auto &r_channel_id) { return r_channel_id.is_error(); })) {
7657 LOG(ERROR) << "Can't parse " << str;
7658 G()->td_db()->get_binlog_pmc()->erase(pmc_key);
7659 } else {
7660 Dependencies dependencies;
7661 vector<ChannelId> channel_ids;
7662 for (auto &r_channel_id : r_channel_ids) {
7663 auto channel_id = r_channel_id.move_as_ok();
7664 add_dialog_and_dependencies(dependencies, DialogId(channel_id));
7665 channel_ids.push_back(channel_id);
7666 }
7667 if (!resolve_dependencies_force(td_, dependencies, "get_created_public_dialogs")) {
7668 G()->td_db()->get_binlog_pmc()->erase(pmc_key);
7669 } else {
7670 created_public_channels_[index] = std::move(channel_ids);
7671 created_public_channels_inited_[index] = true;
7672
7673 if (type == PublicDialogType::HasUsername) {
7674 update_created_public_broadcasts();
7675 }
7676
7677 if (from_binlog) {
7678 return return_created_public_dialogs(std::move(promise), created_public_channels_[index]);
7679 }
7680 }
7681 }
7682 }
7683 }
7684
7685 reload_created_public_dialogs(type, std::move(promise));
7686 }
7687
reload_created_public_dialogs(PublicDialogType type,Promise<td_api::object_ptr<td_api::chats>> && promise)7688 void ContactsManager::reload_created_public_dialogs(PublicDialogType type,
7689 Promise<td_api::object_ptr<td_api::chats>> &&promise) {
7690 auto index = static_cast<int32>(type);
7691 get_created_public_channels_queries_[index].push_back(std::move(promise));
7692 if (get_created_public_channels_queries_[index].size() == 1) {
7693 auto query_promise = PromiseCreator::lambda([actor_id = actor_id(this), type](Result<Unit> &&result) {
7694 send_closure(actor_id, &ContactsManager::finish_get_created_public_dialogs, type, std::move(result));
7695 });
7696 td_->create_handler<GetCreatedPublicChannelsQuery>(std::move(query_promise))->send(type, false);
7697 }
7698 }
7699
finish_get_created_public_dialogs(PublicDialogType type,Result<Unit> && result)7700 void ContactsManager::finish_get_created_public_dialogs(PublicDialogType type, Result<Unit> &&result) {
7701 auto index = static_cast<int32>(type);
7702 auto promises = std::move(get_created_public_channels_queries_[index]);
7703 reset_to_empty(get_created_public_channels_queries_[index]);
7704 if (G()->close_flag()) {
7705 result = G()->close_status();
7706 }
7707 if (result.is_error()) {
7708 for (auto &promise : promises) {
7709 promise.set_error(result.error().clone());
7710 }
7711 return;
7712 }
7713
7714 CHECK(created_public_channels_inited_[index]);
7715 for (auto &promise : promises) {
7716 return_created_public_dialogs(std::move(promise), created_public_channels_[index]);
7717 }
7718 }
7719
update_created_public_channels(Channel * c,ChannelId channel_id)7720 void ContactsManager::update_created_public_channels(Channel *c, ChannelId channel_id) {
7721 if (created_public_channels_inited_[0]) {
7722 bool was_changed = false;
7723 if (c->username.empty() || !c->status.is_creator()) {
7724 was_changed = td::remove(created_public_channels_[0], channel_id);
7725 } else {
7726 if (!td::contains(created_public_channels_[0], channel_id)) {
7727 created_public_channels_[0].push_back(channel_id);
7728 was_changed = true;
7729 }
7730 }
7731 if (was_changed) {
7732 if (!c->is_megagroup) {
7733 update_created_public_broadcasts();
7734 }
7735
7736 save_created_public_channels(PublicDialogType::HasUsername);
7737
7738 reload_created_public_dialogs(PublicDialogType::HasUsername, Promise<td_api::object_ptr<td_api::chats>>());
7739 }
7740 }
7741 if (created_public_channels_inited_[1]) {
7742 bool was_changed = false;
7743 if (!c->has_location || !c->status.is_creator()) {
7744 was_changed = td::remove(created_public_channels_[1], channel_id);
7745 } else {
7746 if (!td::contains(created_public_channels_[1], channel_id)) {
7747 created_public_channels_[1].push_back(channel_id);
7748 was_changed = true;
7749 }
7750 }
7751 if (was_changed) {
7752 save_created_public_channels(PublicDialogType::IsLocationBased);
7753
7754 reload_created_public_dialogs(PublicDialogType::IsLocationBased, Promise<td_api::object_ptr<td_api::chats>>());
7755 }
7756 }
7757 }
7758
on_get_created_public_channels(PublicDialogType type,vector<tl_object_ptr<telegram_api::Chat>> && chats)7759 void ContactsManager::on_get_created_public_channels(PublicDialogType type,
7760 vector<tl_object_ptr<telegram_api::Chat>> &&chats) {
7761 auto index = static_cast<int32>(type);
7762 auto channel_ids = get_channel_ids(std::move(chats), "on_get_created_public_channels");
7763 if (created_public_channels_inited_[index] && created_public_channels_[index] == channel_ids) {
7764 return;
7765 }
7766 for (auto channel_id : channel_ids) {
7767 td_->messages_manager_->force_create_dialog(DialogId(channel_id), "on_get_created_public_channels");
7768 }
7769 created_public_channels_[index] = std::move(channel_ids);
7770 created_public_channels_inited_[index] = true;
7771
7772 if (type == PublicDialogType::HasUsername) {
7773 update_created_public_broadcasts();
7774 }
7775
7776 save_created_public_channels(type);
7777 }
7778
save_created_public_channels(PublicDialogType type)7779 void ContactsManager::save_created_public_channels(PublicDialogType type) {
7780 auto index = static_cast<int32>(type);
7781 CHECK(created_public_channels_inited_[index]);
7782 if (G()->parameters().use_chat_info_db) {
7783 G()->td_db()->get_binlog_pmc()->set(
7784 PSTRING() << "public_channels" << index,
7785 implode(
7786 transform(created_public_channels_[index], [](auto channel_id) { return PSTRING() << channel_id.get(); }),
7787 ','));
7788 }
7789 }
7790
update_created_public_broadcasts()7791 void ContactsManager::update_created_public_broadcasts() {
7792 CHECK(created_public_channels_inited_[0]);
7793 vector<ChannelId> channel_ids;
7794 for (auto &channel_id : created_public_channels_[0]) {
7795 auto c = get_channel(channel_id);
7796 if (!c->is_megagroup) {
7797 channel_ids.push_back(channel_id);
7798 }
7799 }
7800 send_closure_later(G()->messages_manager(), &MessagesManager::on_update_created_public_broadcasts,
7801 std::move(channel_ids));
7802 }
7803
check_created_public_dialogs_limit(PublicDialogType type,Promise<Unit> && promise)7804 void ContactsManager::check_created_public_dialogs_limit(PublicDialogType type, Promise<Unit> &&promise) {
7805 td_->create_handler<GetCreatedPublicChannelsQuery>(std::move(promise))->send(type, true);
7806 }
7807
get_dialogs_for_discussion(Promise<Unit> && promise)7808 vector<DialogId> ContactsManager::get_dialogs_for_discussion(Promise<Unit> &&promise) {
7809 if (dialogs_for_discussion_inited_) {
7810 promise.set_value(Unit());
7811 return transform(dialogs_for_discussion_, [&](DialogId dialog_id) {
7812 td_->messages_manager_->force_create_dialog(dialog_id, "get_dialogs_for_discussion");
7813 return dialog_id;
7814 });
7815 }
7816
7817 td_->create_handler<GetGroupsForDiscussionQuery>(std::move(promise))->send();
7818 return {};
7819 }
7820
on_get_dialogs_for_discussion(vector<tl_object_ptr<telegram_api::Chat>> && chats)7821 void ContactsManager::on_get_dialogs_for_discussion(vector<tl_object_ptr<telegram_api::Chat>> &&chats) {
7822 dialogs_for_discussion_inited_ = true;
7823 dialogs_for_discussion_ = get_dialog_ids(std::move(chats), "on_get_dialogs_for_discussion");
7824 }
7825
update_dialogs_for_discussion(DialogId dialog_id,bool is_suitable)7826 void ContactsManager::update_dialogs_for_discussion(DialogId dialog_id, bool is_suitable) {
7827 if (!dialogs_for_discussion_inited_) {
7828 return;
7829 }
7830
7831 if (is_suitable) {
7832 if (!td::contains(dialogs_for_discussion_, dialog_id)) {
7833 LOG(DEBUG) << "Add " << dialog_id << " to list of suitable discussion chats";
7834 dialogs_for_discussion_.insert(dialogs_for_discussion_.begin(), dialog_id);
7835 }
7836 } else {
7837 if (td::remove(dialogs_for_discussion_, dialog_id)) {
7838 LOG(DEBUG) << "Remove " << dialog_id << " from list of suitable discussion chats";
7839 }
7840 }
7841 }
7842
get_inactive_channels(Promise<Unit> && promise)7843 vector<DialogId> ContactsManager::get_inactive_channels(Promise<Unit> &&promise) {
7844 if (inactive_channels_inited_) {
7845 promise.set_value(Unit());
7846 return transform(inactive_channels_, [&](ChannelId channel_id) {
7847 DialogId dialog_id{channel_id};
7848 td_->messages_manager_->force_create_dialog(dialog_id, "get_inactive_channels");
7849 return dialog_id;
7850 });
7851 }
7852
7853 td_->create_handler<GetInactiveChannelsQuery>(std::move(promise))->send();
7854 return {};
7855 }
7856
on_get_inactive_channels(vector<tl_object_ptr<telegram_api::Chat>> && chats)7857 void ContactsManager::on_get_inactive_channels(vector<tl_object_ptr<telegram_api::Chat>> &&chats) {
7858 inactive_channels_inited_ = true;
7859 inactive_channels_ = get_channel_ids(std::move(chats), "on_get_inactive_channels");
7860 }
7861
remove_inactive_channel(ChannelId channel_id)7862 void ContactsManager::remove_inactive_channel(ChannelId channel_id) {
7863 if (inactive_channels_inited_ && td::remove(inactive_channels_, channel_id)) {
7864 LOG(DEBUG) << "Remove " << channel_id << " from list of inactive channels";
7865 }
7866 }
7867
remove_dialog_suggested_action(SuggestedAction action)7868 void ContactsManager::remove_dialog_suggested_action(SuggestedAction action) {
7869 auto it = dialog_suggested_actions_.find(action.dialog_id_);
7870 if (it == dialog_suggested_actions_.end()) {
7871 return;
7872 }
7873 remove_suggested_action(it->second, action);
7874 if (it->second.empty()) {
7875 dialog_suggested_actions_.erase(it);
7876 }
7877 }
7878
dismiss_dialog_suggested_action(SuggestedAction action,Promise<Unit> && promise)7879 void ContactsManager::dismiss_dialog_suggested_action(SuggestedAction action, Promise<Unit> &&promise) {
7880 auto dialog_id = action.dialog_id_;
7881 if (!td_->messages_manager_->have_dialog(dialog_id)) {
7882 return promise.set_error(Status::Error(400, "Chat not found"));
7883 }
7884 if (!td_->messages_manager_->have_input_peer(dialog_id, AccessRights::Read)) {
7885 return promise.set_error(Status::Error(400, "Can't access the chat"));
7886 }
7887
7888 auto it = dialog_suggested_actions_.find(dialog_id);
7889 if (it == dialog_suggested_actions_.end() || !td::contains(it->second, action)) {
7890 return promise.set_value(Unit());
7891 }
7892
7893 auto action_str = action.get_suggested_action_str();
7894 if (action_str.empty()) {
7895 return promise.set_value(Unit());
7896 }
7897
7898 auto &queries = dismiss_suggested_action_queries_[dialog_id];
7899 queries.push_back(std::move(promise));
7900 if (queries.size() == 1) {
7901 auto query_promise = PromiseCreator::lambda([actor_id = actor_id(this), action](Result<Unit> &&result) {
7902 send_closure(actor_id, &ContactsManager::on_dismiss_suggested_action, action, std::move(result));
7903 });
7904 td_->create_handler<DismissSuggestionQuery>(std::move(query_promise))->send(std::move(action));
7905 }
7906 }
7907
on_dismiss_suggested_action(SuggestedAction action,Result<Unit> && result)7908 void ContactsManager::on_dismiss_suggested_action(SuggestedAction action, Result<Unit> &&result) {
7909 auto it = dismiss_suggested_action_queries_.find(action.dialog_id_);
7910 CHECK(it != dismiss_suggested_action_queries_.end());
7911 auto promises = std::move(it->second);
7912 dismiss_suggested_action_queries_.erase(it);
7913
7914 if (result.is_error()) {
7915 for (auto &promise : promises) {
7916 promise.set_error(result.error().clone());
7917 }
7918 return;
7919 }
7920
7921 remove_dialog_suggested_action(action);
7922
7923 for (auto &promise : promises) {
7924 promise.set_value(Unit());
7925 }
7926 }
7927
on_import_contacts_finished(int64 random_id,vector<UserId> imported_contact_user_ids,vector<int32> unimported_contact_invites)7928 void ContactsManager::on_import_contacts_finished(int64 random_id, vector<UserId> imported_contact_user_ids,
7929 vector<int32> unimported_contact_invites) {
7930 LOG(INFO) << "Contacts import with random_id " << random_id
7931 << " has finished: " << format::as_array(imported_contact_user_ids);
7932 if (random_id == 0) {
7933 // import from change_imported_contacts
7934 all_imported_contacts_ = std::move(next_all_imported_contacts_);
7935 next_all_imported_contacts_.clear();
7936
7937 auto result_size = imported_contacts_unique_id_.size();
7938 auto unique_size = all_imported_contacts_.size();
7939 auto add_size = imported_contacts_pos_.size();
7940
7941 imported_contact_user_ids_.resize(result_size);
7942 unimported_contact_invites_.resize(result_size);
7943
7944 CHECK(imported_contact_user_ids.size() == add_size);
7945 CHECK(unimported_contact_invites.size() == add_size);
7946 CHECK(imported_contacts_unique_id_.size() == result_size);
7947
7948 std::unordered_map<size_t, int32> unique_id_to_unimported_contact_invites;
7949 for (size_t i = 0; i < add_size; i++) {
7950 auto unique_id = imported_contacts_pos_[i];
7951 get_user_id_object(imported_contact_user_ids[i], "on_import_contacts_finished"); // to ensure updateUser
7952 all_imported_contacts_[unique_id].set_user_id(imported_contact_user_ids[i]);
7953 unique_id_to_unimported_contact_invites[unique_id] = unimported_contact_invites[i];
7954 }
7955
7956 if (G()->parameters().use_chat_info_db) {
7957 G()->td_db()->get_binlog()->force_sync(PromiseCreator::lambda(
7958 [log_event = log_event_store(all_imported_contacts_).as_slice().str()](Result<> result) mutable {
7959 if (result.is_ok()) {
7960 LOG(INFO) << "Save imported contacts to database";
7961 G()->td_db()->get_sqlite_pmc()->set("user_imported_contacts", std::move(log_event), Auto());
7962 }
7963 }));
7964 }
7965
7966 for (size_t i = 0; i < result_size; i++) {
7967 auto unique_id = imported_contacts_unique_id_[i];
7968 CHECK(unique_id < unique_size);
7969 imported_contact_user_ids_[i] = all_imported_contacts_[unique_id].get_user_id();
7970 auto it = unique_id_to_unimported_contact_invites.find(unique_id);
7971 if (it == unique_id_to_unimported_contact_invites.end()) {
7972 unimported_contact_invites_[i] = 0;
7973 } else {
7974 unimported_contact_invites_[i] = it->second;
7975 }
7976 }
7977 return;
7978 }
7979
7980 auto it = imported_contacts_.find(random_id);
7981 CHECK(it != imported_contacts_.end());
7982 CHECK(it->second.first.empty());
7983 CHECK(it->second.second.empty());
7984 imported_contacts_[random_id] = {std::move(imported_contact_user_ids), std::move(unimported_contact_invites)};
7985 }
7986
on_deleted_contacts(const vector<UserId> & deleted_contact_user_ids)7987 void ContactsManager::on_deleted_contacts(const vector<UserId> &deleted_contact_user_ids) {
7988 LOG(INFO) << "Contacts deletion has finished for " << deleted_contact_user_ids;
7989
7990 for (auto user_id : deleted_contact_user_ids) {
7991 auto u = get_user(user_id);
7992 CHECK(u != nullptr);
7993 if (!u->is_contact) {
7994 continue;
7995 }
7996
7997 LOG(INFO) << "Drop contact with " << user_id;
7998 on_update_user_is_contact(u, user_id, false, false);
7999 CHECK(u->is_is_contact_changed);
8000 u->cache_version = 0;
8001 u->is_repaired = false;
8002 update_user(u, user_id);
8003 CHECK(!u->is_contact);
8004 CHECK(!contacts_hints_.has_key(user_id.get()));
8005 }
8006 }
8007
save_next_contacts_sync_date()8008 void ContactsManager::save_next_contacts_sync_date() {
8009 if (G()->close_flag()) {
8010 return;
8011 }
8012 if (!G()->parameters().use_chat_info_db) {
8013 return;
8014 }
8015 G()->td_db()->get_binlog_pmc()->set("next_contacts_sync_date", to_string(next_contacts_sync_date_));
8016 }
8017
on_get_contacts(tl_object_ptr<telegram_api::contacts_Contacts> && new_contacts)8018 void ContactsManager::on_get_contacts(tl_object_ptr<telegram_api::contacts_Contacts> &&new_contacts) {
8019 next_contacts_sync_date_ = G()->unix_time() + Random::fast(70000, 100000);
8020
8021 CHECK(new_contacts != nullptr);
8022 if (new_contacts->get_id() == telegram_api::contacts_contactsNotModified::ID) {
8023 if (saved_contact_count_ == -1) {
8024 saved_contact_count_ = 0;
8025 }
8026 on_get_contacts_finished(contacts_hints_.size());
8027 td_->create_handler<GetContactsStatusesQuery>()->send();
8028 return;
8029 }
8030
8031 auto contacts = move_tl_object_as<telegram_api::contacts_contacts>(new_contacts);
8032 std::unordered_set<UserId, UserIdHash> contact_user_ids;
8033 for (auto &user : contacts->users_) {
8034 auto user_id = get_user_id(user);
8035 if (!user_id.is_valid()) {
8036 LOG(ERROR) << "Receive invalid " << user_id;
8037 continue;
8038 }
8039 contact_user_ids.insert(user_id);
8040 }
8041 on_get_users(std::move(contacts->users_), "on_get_contacts");
8042
8043 UserId my_id = get_my_id();
8044 for (auto &p : users_) {
8045 UserId user_id = p.first;
8046 User *u = p.second.get();
8047 bool should_be_contact = contact_user_ids.count(user_id) == 1;
8048 if (u->is_contact != should_be_contact) {
8049 if (u->is_contact) {
8050 LOG(INFO) << "Drop contact with " << user_id;
8051 if (user_id != my_id) {
8052 LOG_CHECK(contacts_hints_.has_key(user_id.get()))
8053 << my_id << " " << user_id << " " << to_string(get_user_object(user_id, u));
8054 }
8055 on_update_user_is_contact(u, user_id, false, false);
8056 CHECK(u->is_is_contact_changed);
8057 u->cache_version = 0;
8058 u->is_repaired = false;
8059 update_user(u, user_id);
8060 CHECK(!u->is_contact);
8061 if (user_id != my_id) {
8062 CHECK(!contacts_hints_.has_key(user_id.get()));
8063 }
8064 } else {
8065 LOG(ERROR) << "Receive non-contact " << user_id << " in the list of contacts";
8066 }
8067 }
8068 }
8069
8070 saved_contact_count_ = contacts->saved_count_;
8071 on_get_contacts_finished(std::numeric_limits<size_t>::max());
8072 }
8073
save_contacts_to_database()8074 void ContactsManager::save_contacts_to_database() {
8075 if (!G()->parameters().use_chat_info_db || !are_contacts_loaded_) {
8076 return;
8077 }
8078
8079 LOG(INFO) << "Schedule save contacts to database";
8080 vector<UserId> user_ids =
8081 transform(contacts_hints_.search_empty(100000).second, [](int64 key) { return UserId(key); });
8082
8083 G()->td_db()->get_binlog_pmc()->set("saved_contact_count", to_string(saved_contact_count_));
8084 G()->td_db()->get_binlog()->force_sync(PromiseCreator::lambda([user_ids = std::move(user_ids)](Result<> result) {
8085 if (result.is_ok()) {
8086 LOG(INFO) << "Save contacts to database";
8087 G()->td_db()->get_sqlite_pmc()->set(
8088 "user_contacts", log_event_store(user_ids).as_slice().str(), PromiseCreator::lambda([](Result<> result) {
8089 if (result.is_ok()) {
8090 send_closure(G()->contacts_manager(), &ContactsManager::save_next_contacts_sync_date);
8091 }
8092 }));
8093 }
8094 }));
8095 }
8096
on_get_contacts_failed(Status error)8097 void ContactsManager::on_get_contacts_failed(Status error) {
8098 CHECK(error.is_error());
8099 next_contacts_sync_date_ = G()->unix_time() + Random::fast(5, 10);
8100 auto promises = std::move(load_contacts_queries_);
8101 load_contacts_queries_.clear();
8102 for (auto &promise : promises) {
8103 promise.set_error(error.clone());
8104 }
8105 }
8106
on_load_contacts_from_database(string value)8107 void ContactsManager::on_load_contacts_from_database(string value) {
8108 if (G()->close_flag()) {
8109 return;
8110 }
8111 if (value.empty()) {
8112 reload_contacts(true);
8113 return;
8114 }
8115
8116 vector<UserId> user_ids;
8117 log_event_parse(user_ids, value).ensure();
8118
8119 LOG(INFO) << "Successfully loaded " << user_ids.size() << " contacts from database";
8120
8121 load_contact_users_multipromise_.add_promise(PromiseCreator::lambda(
8122 [actor_id = actor_id(this), expected_contact_count = user_ids.size()](Result<Unit> result) {
8123 if (result.is_ok()) {
8124 send_closure(actor_id, &ContactsManager::on_get_contacts_finished, expected_contact_count);
8125 }
8126 }));
8127
8128 auto lock_promise = load_contact_users_multipromise_.get_promise();
8129
8130 for (auto user_id : user_ids) {
8131 get_user(user_id, 3, load_contact_users_multipromise_.get_promise());
8132 }
8133
8134 lock_promise.set_value(Unit());
8135 }
8136
on_get_contacts_finished(size_t expected_contact_count)8137 void ContactsManager::on_get_contacts_finished(size_t expected_contact_count) {
8138 LOG(INFO) << "Finished to get " << contacts_hints_.size() << " contacts out of expected " << expected_contact_count;
8139 are_contacts_loaded_ = true;
8140 auto promises = std::move(load_contacts_queries_);
8141 load_contacts_queries_.clear();
8142 for (auto &promise : promises) {
8143 promise.set_value(Unit());
8144 }
8145 if (expected_contact_count != contacts_hints_.size()) {
8146 save_contacts_to_database();
8147 }
8148 }
8149
on_get_contacts_statuses(vector<tl_object_ptr<telegram_api::contactStatus>> && statuses)8150 void ContactsManager::on_get_contacts_statuses(vector<tl_object_ptr<telegram_api::contactStatus>> &&statuses) {
8151 auto my_user_id = get_my_id();
8152 for (auto &status : statuses) {
8153 UserId user_id(status->user_id_);
8154 if (user_id != my_user_id) {
8155 on_update_user_online(user_id, std::move(status->status_));
8156 }
8157 }
8158 save_next_contacts_sync_date();
8159 }
8160
on_update_online_status_privacy()8161 void ContactsManager::on_update_online_status_privacy() {
8162 td_->create_handler<GetContactsStatusesQuery>()->send();
8163 }
8164
on_update_phone_number_privacy()8165 void ContactsManager::on_update_phone_number_privacy() {
8166 // all UserFull.need_phone_number_privacy_exception can be outdated now,
8167 // so mark all of them as expired
8168 for (auto &it : users_full_) {
8169 it.second->expires_at = 0.0;
8170 }
8171 }
8172
invalidate_user_full(UserId user_id)8173 void ContactsManager::invalidate_user_full(UserId user_id) {
8174 auto user_full = get_user_full_force(user_id);
8175 if (user_full != nullptr) {
8176 td_->messages_manager_->on_dialog_info_full_invalidated(DialogId(user_id));
8177
8178 if (!user_full->is_expired()) {
8179 user_full->expires_at = 0.0;
8180 user_full->need_save_to_database = true;
8181
8182 update_user_full(user_full, user_id, "invalidate_user_full");
8183 }
8184 }
8185 }
8186
get_user_id(const tl_object_ptr<telegram_api::User> & user)8187 UserId ContactsManager::get_user_id(const tl_object_ptr<telegram_api::User> &user) {
8188 CHECK(user != nullptr);
8189 switch (user->get_id()) {
8190 case telegram_api::userEmpty::ID:
8191 return UserId(static_cast<const telegram_api::userEmpty *>(user.get())->id_);
8192 case telegram_api::user::ID:
8193 return UserId(static_cast<const telegram_api::user *>(user.get())->id_);
8194 default:
8195 UNREACHABLE();
8196 return UserId();
8197 }
8198 }
8199
get_chat_id(const tl_object_ptr<telegram_api::Chat> & chat)8200 ChatId ContactsManager::get_chat_id(const tl_object_ptr<telegram_api::Chat> &chat) {
8201 CHECK(chat != nullptr);
8202 switch (chat->get_id()) {
8203 case telegram_api::chatEmpty::ID:
8204 return ChatId(static_cast<const telegram_api::chatEmpty *>(chat.get())->id_);
8205 case telegram_api::chat::ID:
8206 return ChatId(static_cast<const telegram_api::chat *>(chat.get())->id_);
8207 case telegram_api::chatForbidden::ID:
8208 return ChatId(static_cast<const telegram_api::chatForbidden *>(chat.get())->id_);
8209 default:
8210 return ChatId();
8211 }
8212 }
8213
get_channel_id(const tl_object_ptr<telegram_api::Chat> & chat)8214 ChannelId ContactsManager::get_channel_id(const tl_object_ptr<telegram_api::Chat> &chat) {
8215 CHECK(chat != nullptr);
8216 switch (chat->get_id()) {
8217 case telegram_api::channel::ID:
8218 return ChannelId(static_cast<const telegram_api::channel *>(chat.get())->id_);
8219 case telegram_api::channelForbidden::ID:
8220 return ChannelId(static_cast<const telegram_api::channelForbidden *>(chat.get())->id_);
8221 default:
8222 return ChannelId();
8223 }
8224 }
8225
on_get_user(tl_object_ptr<telegram_api::User> && user_ptr,const char * source,bool is_me,bool expect_support)8226 void ContactsManager::on_get_user(tl_object_ptr<telegram_api::User> &&user_ptr, const char *source, bool is_me,
8227 bool expect_support) {
8228 LOG(DEBUG) << "Receive from " << source << ' ' << to_string(user_ptr);
8229 int32 constructor_id = user_ptr->get_id();
8230 if (constructor_id == telegram_api::userEmpty::ID) {
8231 auto user = move_tl_object_as<telegram_api::userEmpty>(user_ptr);
8232 UserId user_id(user->id_);
8233 if (!user_id.is_valid()) {
8234 LOG(ERROR) << "Receive invalid " << user_id << " from " << source;
8235 return;
8236 }
8237 LOG(INFO) << "Receive empty " << user_id << " from " << source;
8238
8239 User *u = get_user_force(user_id);
8240 if (u == nullptr && Slice(source) != Slice("GetUsersQuery")) {
8241 // userEmpty should be received only through getUsers for unexisting users
8242 LOG(ERROR) << "Have no information about " << user_id << ", but received userEmpty from " << source;
8243 }
8244 return;
8245 }
8246
8247 CHECK(constructor_id == telegram_api::user::ID);
8248 auto user = move_tl_object_as<telegram_api::user>(user_ptr);
8249 UserId user_id(user->id_);
8250 if (!user_id.is_valid()) {
8251 LOG(ERROR) << "Receive invalid " << user_id;
8252 return;
8253 }
8254 int32 flags = user->flags_;
8255 LOG(INFO) << "Receive " << user_id << " with flags " << flags << " from " << source;
8256 if (is_me && (flags & USER_FLAG_IS_ME) == 0) {
8257 LOG(ERROR) << user_id << " doesn't have flag IS_ME, but must have it when received from " << source;
8258 flags |= USER_FLAG_IS_ME;
8259 }
8260
8261 bool is_bot = (flags & USER_FLAG_IS_BOT) != 0;
8262 if (flags & USER_FLAG_IS_ME) {
8263 set_my_id(user_id);
8264 if (!is_bot) {
8265 G()->shared_config().set_option_string("my_phone_number", user->phone_);
8266 }
8267 }
8268
8269 if (expect_support) {
8270 support_user_id_ = user_id;
8271 }
8272
8273 bool have_access_hash = (flags & USER_FLAG_HAS_ACCESS_HASH) != 0;
8274 bool is_received = (flags & USER_FLAG_IS_INACCESSIBLE) == 0;
8275
8276 if (!is_received && !have_user_force(user_id)) {
8277 // we must preload information about received inaccessible users from database in order to not save
8278 // the min-user to the database and to not override access_hash and another info
8279 LOG(INFO) << "Receive inaccessible " << user_id;
8280 }
8281
8282 User *u = add_user(user_id, "on_get_user");
8283 if (have_access_hash) { // access_hash must be updated before photo
8284 auto access_hash = user->access_hash_;
8285 bool is_min_access_hash = !is_received && !((flags & USER_FLAG_HAS_PHONE_NUMBER) != 0 && user->phone_.empty());
8286 if (u->access_hash != access_hash && (!is_min_access_hash || u->is_min_access_hash || u->access_hash == -1)) {
8287 LOG(DEBUG) << "Access hash has changed for " << user_id << " from " << u->access_hash << "/"
8288 << u->is_min_access_hash << " to " << access_hash << "/" << is_min_access_hash;
8289 u->access_hash = access_hash;
8290 u->is_min_access_hash = is_min_access_hash;
8291 u->need_save_to_database = true;
8292 }
8293 }
8294 if (is_received || !user->phone_.empty()) {
8295 on_update_user_phone_number(u, user_id, std::move(user->phone_));
8296 }
8297 if (is_received || u->need_apply_min_photo || !u->is_received) {
8298 on_update_user_photo(u, user_id, std::move(user->photo_), source);
8299 }
8300 if (is_received) {
8301 on_update_user_online(u, user_id, std::move(user->status_));
8302
8303 auto is_contact = (flags & USER_FLAG_IS_CONTACT) != 0;
8304 auto is_mutual_contact = (flags & USER_FLAG_IS_MUTUAL_CONTACT) != 0;
8305 on_update_user_is_contact(u, user_id, is_contact, is_mutual_contact);
8306 }
8307
8308 if (is_received || !u->is_received) {
8309 on_update_user_name(u, user_id, std::move(user->first_name_), std::move(user->last_name_),
8310 std::move(user->username_));
8311 }
8312
8313 bool is_verified = (flags & USER_FLAG_IS_VERIFIED) != 0;
8314 bool is_support = (flags & USER_FLAG_IS_SUPPORT) != 0;
8315 bool is_deleted = (flags & USER_FLAG_IS_DELETED) != 0;
8316 bool can_join_groups = (flags & USER_FLAG_IS_PRIVATE_BOT) == 0;
8317 bool can_read_all_group_messages = (flags & USER_FLAG_IS_BOT_WITH_PRIVACY_DISABLED) != 0;
8318 auto restriction_reasons = get_restriction_reasons(std::move(user->restriction_reason_));
8319 bool is_scam = (flags & USER_FLAG_IS_SCAM) != 0;
8320 bool is_inline_bot = (flags & USER_FLAG_IS_INLINE_BOT) != 0;
8321 string inline_query_placeholder = user->bot_inline_placeholder_;
8322 bool need_location_bot = (flags & USER_FLAG_NEED_LOCATION_BOT) != 0;
8323 bool has_bot_info_version = (flags & USER_FLAG_HAS_BOT_INFO_VERSION) != 0;
8324 bool need_apply_min_photo = (flags & USER_FLAG_NEED_APPLY_MIN_PHOTO) != 0;
8325 bool is_fake = (flags & USER_FLAG_IS_FAKE) != 0;
8326
8327 LOG_IF(ERROR, !is_support && expect_support) << "Receive non-support " << user_id << ", but expected a support user";
8328 LOG_IF(ERROR, !can_join_groups && !is_bot)
8329 << "Receive not bot " << user_id << " which can't join groups from " << source;
8330 LOG_IF(ERROR, can_read_all_group_messages && !is_bot)
8331 << "Receive not bot " << user_id << " which can read all group messages from " << source;
8332 LOG_IF(ERROR, is_inline_bot && !is_bot) << "Receive not bot " << user_id << " which is inline bot from " << source;
8333 LOG_IF(ERROR, need_location_bot && !is_inline_bot)
8334 << "Receive not inline bot " << user_id << " which needs user location from " << source;
8335
8336 if (is_deleted) {
8337 // just in case
8338 is_verified = false;
8339 is_support = false;
8340 is_bot = false;
8341 can_join_groups = false;
8342 can_read_all_group_messages = false;
8343 is_inline_bot = false;
8344 inline_query_placeholder = string();
8345 need_location_bot = false;
8346 has_bot_info_version = false;
8347 need_apply_min_photo = false;
8348 }
8349
8350 LOG_IF(ERROR, has_bot_info_version && !is_bot)
8351 << "Receive not bot " << user_id << " which has bot info version from " << source;
8352
8353 int32 bot_info_version = has_bot_info_version ? user->bot_info_version_ : -1;
8354 if (is_verified != u->is_verified || is_support != u->is_support || is_bot != u->is_bot ||
8355 can_join_groups != u->can_join_groups || can_read_all_group_messages != u->can_read_all_group_messages ||
8356 restriction_reasons != u->restriction_reasons || is_scam != u->is_scam || is_fake != u->is_fake ||
8357 is_inline_bot != u->is_inline_bot || inline_query_placeholder != u->inline_query_placeholder ||
8358 need_location_bot != u->need_location_bot) {
8359 LOG_IF(ERROR, is_bot != u->is_bot && !is_deleted && !u->is_deleted && u->is_received)
8360 << "User.is_bot has changed for " << user_id << "/" << u->username << " from " << source << " from "
8361 << u->is_bot << " to " << is_bot;
8362 u->is_verified = is_verified;
8363 u->is_support = is_support;
8364 u->is_bot = is_bot;
8365 u->can_join_groups = can_join_groups;
8366 u->can_read_all_group_messages = can_read_all_group_messages;
8367 u->restriction_reasons = std::move(restriction_reasons);
8368 u->is_scam = is_scam;
8369 u->is_fake = is_fake;
8370 u->is_inline_bot = is_inline_bot;
8371 u->inline_query_placeholder = std::move(inline_query_placeholder);
8372 u->need_location_bot = need_location_bot;
8373
8374 LOG(DEBUG) << "Info has changed for " << user_id;
8375 u->is_changed = true;
8376 }
8377
8378 if (u->bot_info_version != bot_info_version) {
8379 u->bot_info_version = bot_info_version;
8380 LOG(DEBUG) << "Bot info version has changed for " << user_id;
8381 u->need_save_to_database = true;
8382 }
8383 if (is_received && u->need_apply_min_photo != need_apply_min_photo) {
8384 u->need_apply_min_photo = need_apply_min_photo;
8385 u->need_save_to_database = true;
8386 }
8387
8388 if (is_received && !u->is_received) {
8389 u->is_received = true;
8390
8391 LOG(DEBUG) << "Receive " << user_id;
8392 u->is_changed = true;
8393 }
8394
8395 if (is_deleted != u->is_deleted) {
8396 u->is_deleted = is_deleted;
8397
8398 LOG(DEBUG) << "User.is_deleted has changed for " << user_id << " to " << u->is_deleted;
8399 u->is_is_deleted_changed = true;
8400 u->is_changed = true;
8401 }
8402
8403 bool has_language_code = (flags & USER_FLAG_HAS_LANGUAGE_CODE) != 0;
8404 LOG_IF(ERROR, has_language_code && !td_->auth_manager_->is_bot())
8405 << "Receive language code for " << user_id << " from " << source;
8406 if (u->language_code != user->lang_code_ && !user->lang_code_.empty()) {
8407 u->language_code = user->lang_code_;
8408
8409 LOG(DEBUG) << "Language code has changed for " << user_id << " to " << u->language_code;
8410 u->is_changed = true;
8411 }
8412
8413 if (u->cache_version != User::CACHE_VERSION && u->is_received) {
8414 u->cache_version = User::CACHE_VERSION;
8415 u->need_save_to_database = true;
8416 }
8417 u->is_received_from_server = true;
8418 update_user(u, user_id);
8419 }
8420
8421 class ContactsManager::UserLogEvent {
8422 public:
8423 UserId user_id;
8424 User u;
8425
8426 UserLogEvent() = default;
8427
UserLogEvent(UserId user_id,const User & u)8428 UserLogEvent(UserId user_id, const User &u) : user_id(user_id), u(u) {
8429 }
8430
8431 template <class StorerT>
store(StorerT & storer) const8432 void store(StorerT &storer) const {
8433 td::store(user_id, storer);
8434 td::store(u, storer);
8435 }
8436
8437 template <class ParserT>
parse(ParserT & parser)8438 void parse(ParserT &parser) {
8439 td::parse(user_id, parser);
8440 td::parse(u, parser);
8441 }
8442 };
8443
save_user(User * u,UserId user_id,bool from_binlog)8444 void ContactsManager::save_user(User *u, UserId user_id, bool from_binlog) {
8445 if (!G()->parameters().use_chat_info_db) {
8446 return;
8447 }
8448 CHECK(u != nullptr);
8449 if (!u->is_saved || !u->is_status_saved) { // TODO more effective handling of !u->is_status_saved
8450 if (!from_binlog) {
8451 auto log_event = UserLogEvent(user_id, *u);
8452 auto storer = get_log_event_storer(log_event);
8453 if (u->log_event_id == 0) {
8454 u->log_event_id = binlog_add(G()->td_db()->get_binlog(), LogEvent::HandlerType::Users, storer);
8455 } else {
8456 binlog_rewrite(G()->td_db()->get_binlog(), u->log_event_id, LogEvent::HandlerType::Users, storer);
8457 }
8458 }
8459
8460 save_user_to_database(u, user_id);
8461 }
8462 }
8463
on_binlog_user_event(BinlogEvent && event)8464 void ContactsManager::on_binlog_user_event(BinlogEvent &&event) {
8465 if (!G()->parameters().use_chat_info_db) {
8466 binlog_erase(G()->td_db()->get_binlog(), event.id_);
8467 return;
8468 }
8469
8470 UserLogEvent log_event;
8471 log_event_parse(log_event, event.data_).ensure();
8472
8473 auto user_id = log_event.user_id;
8474 if (have_user(user_id)) {
8475 LOG(ERROR) << "Skip adding already added " << user_id;
8476 binlog_erase(G()->td_db()->get_binlog(), event.id_);
8477 return;
8478 }
8479
8480 LOG(INFO) << "Add " << user_id << " from binlog";
8481 User *u = add_user(user_id, "on_binlog_user_event");
8482 *u = std::move(log_event.u); // users come from binlog before all other events, so just add them
8483
8484 u->log_event_id = event.id_;
8485
8486 update_user(u, user_id, true, false);
8487 }
8488
get_user_database_key(UserId user_id)8489 string ContactsManager::get_user_database_key(UserId user_id) {
8490 return PSTRING() << "us" << user_id.get();
8491 }
8492
get_user_database_value(const User * u)8493 string ContactsManager::get_user_database_value(const User *u) {
8494 return log_event_store(*u).as_slice().str();
8495 }
8496
save_user_to_database(User * u,UserId user_id)8497 void ContactsManager::save_user_to_database(User *u, UserId user_id) {
8498 CHECK(u != nullptr);
8499 if (u->is_being_saved) {
8500 return;
8501 }
8502 if (loaded_from_database_users_.count(user_id)) {
8503 save_user_to_database_impl(u, user_id, get_user_database_value(u));
8504 return;
8505 }
8506 if (load_user_from_database_queries_.count(user_id) != 0) {
8507 return;
8508 }
8509
8510 load_user_from_database_impl(user_id, Auto());
8511 }
8512
save_user_to_database_impl(User * u,UserId user_id,string value)8513 void ContactsManager::save_user_to_database_impl(User *u, UserId user_id, string value) {
8514 CHECK(u != nullptr);
8515 CHECK(load_user_from_database_queries_.count(user_id) == 0);
8516 CHECK(!u->is_being_saved);
8517 u->is_being_saved = true;
8518 u->is_saved = true;
8519 u->is_status_saved = true;
8520 LOG(INFO) << "Trying to save to database " << user_id;
8521 G()->td_db()->get_sqlite_pmc()->set(
8522 get_user_database_key(user_id), std::move(value), PromiseCreator::lambda([user_id](Result<> result) {
8523 send_closure(G()->contacts_manager(), &ContactsManager::on_save_user_to_database, user_id, result.is_ok());
8524 }));
8525 }
8526
on_save_user_to_database(UserId user_id,bool success)8527 void ContactsManager::on_save_user_to_database(UserId user_id, bool success) {
8528 if (G()->close_flag()) {
8529 return;
8530 }
8531
8532 User *u = get_user(user_id);
8533 CHECK(u != nullptr);
8534 LOG_CHECK(u->is_being_saved) << user_id << " " << u->is_saved << " " << u->is_status_saved << " "
8535 << load_user_from_database_queries_.count(user_id) << " " << u->is_received << " "
8536 << u->is_deleted << " " << u->is_bot << " " << u->need_save_to_database << " "
8537 << u->is_changed << " " << u->is_status_changed << " " << u->is_name_changed << " "
8538 << u->is_username_changed << " " << u->is_photo_changed << " "
8539 << u->is_is_contact_changed << " " << u->is_is_deleted_changed;
8540 CHECK(load_user_from_database_queries_.count(user_id) == 0);
8541 u->is_being_saved = false;
8542
8543 if (!success) {
8544 LOG(ERROR) << "Failed to save " << user_id << " to database";
8545 u->is_saved = false;
8546 u->is_status_saved = false;
8547 } else {
8548 LOG(INFO) << "Successfully saved " << user_id << " to database";
8549 }
8550 if (u->is_saved && u->is_status_saved) {
8551 if (u->log_event_id != 0) {
8552 binlog_erase(G()->td_db()->get_binlog(), u->log_event_id);
8553 u->log_event_id = 0;
8554 }
8555 } else {
8556 save_user(u, user_id, u->log_event_id != 0);
8557 }
8558 }
8559
load_user_from_database(User * u,UserId user_id,Promise<Unit> promise)8560 void ContactsManager::load_user_from_database(User *u, UserId user_id, Promise<Unit> promise) {
8561 if (loaded_from_database_users_.count(user_id)) {
8562 promise.set_value(Unit());
8563 return;
8564 }
8565
8566 CHECK(u == nullptr || !u->is_being_saved);
8567 load_user_from_database_impl(user_id, std::move(promise));
8568 }
8569
load_user_from_database_impl(UserId user_id,Promise<Unit> promise)8570 void ContactsManager::load_user_from_database_impl(UserId user_id, Promise<Unit> promise) {
8571 LOG(INFO) << "Load " << user_id << " from database";
8572 auto &load_user_queries = load_user_from_database_queries_[user_id];
8573 load_user_queries.push_back(std::move(promise));
8574 if (load_user_queries.size() == 1u) {
8575 G()->td_db()->get_sqlite_pmc()->get(get_user_database_key(user_id), PromiseCreator::lambda([user_id](string value) {
8576 send_closure(G()->contacts_manager(),
8577 &ContactsManager::on_load_user_from_database, user_id,
8578 std::move(value), false);
8579 }));
8580 }
8581 }
8582
on_load_user_from_database(UserId user_id,string value,bool force)8583 void ContactsManager::on_load_user_from_database(UserId user_id, string value, bool force) {
8584 if (G()->close_flag() && !force) {
8585 // the user is in Binlog and will be saved after restart
8586 return;
8587 }
8588
8589 if (!loaded_from_database_users_.insert(user_id).second) {
8590 return;
8591 }
8592
8593 auto it = load_user_from_database_queries_.find(user_id);
8594 vector<Promise<Unit>> promises;
8595 if (it != load_user_from_database_queries_.end()) {
8596 promises = std::move(it->second);
8597 CHECK(!promises.empty());
8598 load_user_from_database_queries_.erase(it);
8599 }
8600
8601 LOG(INFO) << "Successfully loaded " << user_id << " of size " << value.size() << " from database";
8602 // G()->td_db()->get_sqlite_pmc()->erase(get_user_database_key(user_id), Auto());
8603 // return;
8604
8605 User *u = get_user(user_id);
8606 if (u == nullptr) {
8607 if (!value.empty()) {
8608 u = add_user(user_id, "on_load_user_from_database");
8609
8610 log_event_parse(*u, value).ensure();
8611
8612 u->is_saved = true;
8613 u->is_status_saved = true;
8614 update_user(u, user_id, true, true);
8615 }
8616 } else {
8617 CHECK(!u->is_saved); // user can't be saved before load completes
8618 CHECK(!u->is_being_saved);
8619 auto new_value = get_user_database_value(u);
8620 if (value != new_value) {
8621 save_user_to_database_impl(u, user_id, std::move(new_value));
8622 } else if (u->log_event_id != 0) {
8623 binlog_erase(G()->td_db()->get_binlog(), u->log_event_id);
8624 u->log_event_id = 0;
8625 }
8626 }
8627
8628 for (auto &promise : promises) {
8629 promise.set_value(Unit());
8630 }
8631 }
8632
have_user_force(UserId user_id)8633 bool ContactsManager::have_user_force(UserId user_id) {
8634 return get_user_force(user_id) != nullptr;
8635 }
8636
get_user_force(UserId user_id)8637 ContactsManager::User *ContactsManager::get_user_force(UserId user_id) {
8638 auto u = get_user_force_impl(user_id);
8639 if ((u == nullptr || !u->is_received) &&
8640 (user_id == get_service_notifications_user_id() || user_id == get_replies_bot_user_id() ||
8641 user_id == get_anonymous_bot_user_id())) {
8642 int32 flags = USER_FLAG_HAS_ACCESS_HASH | USER_FLAG_HAS_FIRST_NAME | USER_FLAG_NEED_APPLY_MIN_PHOTO;
8643 int64 profile_photo_id = 0;
8644 int32 profile_photo_dc_id = 1;
8645 string first_name;
8646 string last_name;
8647 string username;
8648 string phone_number;
8649 int32 bot_info_version = 0;
8650
8651 if (user_id == get_service_notifications_user_id()) {
8652 flags |= USER_FLAG_HAS_PHONE_NUMBER | USER_FLAG_IS_VERIFIED | USER_FLAG_IS_SUPPORT;
8653 first_name = "Telegram";
8654 if (G()->is_test_dc()) {
8655 flags |= USER_FLAG_HAS_LAST_NAME;
8656 last_name = "Notifications";
8657 }
8658 phone_number = "42777";
8659 profile_photo_id = 3337190045231023;
8660 } else if (user_id == get_replies_bot_user_id()) {
8661 flags |= USER_FLAG_HAS_USERNAME | USER_FLAG_IS_BOT;
8662 if (!G()->is_test_dc()) {
8663 flags |= USER_FLAG_IS_PRIVATE_BOT;
8664 }
8665 first_name = "Replies";
8666 username = "replies";
8667 bot_info_version = G()->is_test_dc() ? 1 : 3;
8668 } else if (user_id == get_anonymous_bot_user_id()) {
8669 flags |= USER_FLAG_HAS_USERNAME | USER_FLAG_IS_BOT;
8670 if (!G()->is_test_dc()) {
8671 flags |= USER_FLAG_IS_PRIVATE_BOT;
8672 }
8673 first_name = "Group";
8674 username = G()->is_test_dc() ? "izgroupbot" : "GroupAnonymousBot";
8675 bot_info_version = G()->is_test_dc() ? 1 : 3;
8676 profile_photo_id = 5159307831025969322;
8677 }
8678
8679 telegram_api::object_ptr<telegram_api::userProfilePhoto> profile_photo;
8680 if (!G()->is_test_dc() && profile_photo_id != 0) {
8681 profile_photo = telegram_api::make_object<telegram_api::userProfilePhoto>(0, false /*ignored*/, profile_photo_id,
8682 BufferSlice(), profile_photo_dc_id);
8683 }
8684
8685 auto user = telegram_api::make_object<telegram_api::user>(
8686 flags, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/,
8687 false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/,
8688 false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, user_id.get(), 1,
8689 first_name, string(), username, phone_number, std::move(profile_photo), nullptr, bot_info_version, Auto(),
8690 string(), string());
8691 on_get_user(std::move(user), "get_user_force");
8692 u = get_user(user_id);
8693 CHECK(u != nullptr && u->is_received);
8694 }
8695 return u;
8696 }
8697
get_user_force_impl(UserId user_id)8698 ContactsManager::User *ContactsManager::get_user_force_impl(UserId user_id) {
8699 if (!user_id.is_valid()) {
8700 return nullptr;
8701 }
8702
8703 User *u = get_user(user_id);
8704 if (u != nullptr) {
8705 return u;
8706 }
8707 if (!G()->parameters().use_chat_info_db) {
8708 return nullptr;
8709 }
8710 if (loaded_from_database_users_.count(user_id)) {
8711 return nullptr;
8712 }
8713
8714 LOG(INFO) << "Trying to load " << user_id << " from database";
8715 on_load_user_from_database(user_id, G()->td_db()->get_sqlite_sync_pmc()->get(get_user_database_key(user_id)), true);
8716 return get_user(user_id);
8717 }
8718
8719 class ContactsManager::ChatLogEvent {
8720 public:
8721 ChatId chat_id;
8722 Chat c;
8723
8724 ChatLogEvent() = default;
8725
ChatLogEvent(ChatId chat_id,const Chat & c)8726 ChatLogEvent(ChatId chat_id, const Chat &c) : chat_id(chat_id), c(c) {
8727 }
8728
8729 template <class StorerT>
store(StorerT & storer) const8730 void store(StorerT &storer) const {
8731 td::store(chat_id, storer);
8732 td::store(c, storer);
8733 }
8734
8735 template <class ParserT>
parse(ParserT & parser)8736 void parse(ParserT &parser) {
8737 td::parse(chat_id, parser);
8738 td::parse(c, parser);
8739 }
8740 };
8741
save_chat(Chat * c,ChatId chat_id,bool from_binlog)8742 void ContactsManager::save_chat(Chat *c, ChatId chat_id, bool from_binlog) {
8743 if (!G()->parameters().use_chat_info_db) {
8744 return;
8745 }
8746 CHECK(c != nullptr);
8747 if (!c->is_saved) {
8748 if (!from_binlog) {
8749 auto log_event = ChatLogEvent(chat_id, *c);
8750 auto storer = get_log_event_storer(log_event);
8751 if (c->log_event_id == 0) {
8752 c->log_event_id = binlog_add(G()->td_db()->get_binlog(), LogEvent::HandlerType::Chats, storer);
8753 } else {
8754 binlog_rewrite(G()->td_db()->get_binlog(), c->log_event_id, LogEvent::HandlerType::Chats, storer);
8755 }
8756 }
8757
8758 save_chat_to_database(c, chat_id);
8759 return;
8760 }
8761 }
8762
on_binlog_chat_event(BinlogEvent && event)8763 void ContactsManager::on_binlog_chat_event(BinlogEvent &&event) {
8764 if (!G()->parameters().use_chat_info_db) {
8765 binlog_erase(G()->td_db()->get_binlog(), event.id_);
8766 return;
8767 }
8768
8769 ChatLogEvent log_event;
8770 log_event_parse(log_event, event.data_).ensure();
8771
8772 auto chat_id = log_event.chat_id;
8773 if (have_chat(chat_id)) {
8774 LOG(ERROR) << "Skip adding already added " << chat_id;
8775 binlog_erase(G()->td_db()->get_binlog(), event.id_);
8776 return;
8777 }
8778
8779 LOG(INFO) << "Add " << chat_id << " from binlog";
8780 Chat *c = add_chat(chat_id);
8781 *c = std::move(log_event.c); // chats come from binlog before all other events, so just add them
8782
8783 c->log_event_id = event.id_;
8784
8785 update_chat(c, chat_id, true, false);
8786 }
8787
get_chat_database_key(ChatId chat_id)8788 string ContactsManager::get_chat_database_key(ChatId chat_id) {
8789 return PSTRING() << "gr" << chat_id.get();
8790 }
8791
get_chat_database_value(const Chat * c)8792 string ContactsManager::get_chat_database_value(const Chat *c) {
8793 return log_event_store(*c).as_slice().str();
8794 }
8795
save_chat_to_database(Chat * c,ChatId chat_id)8796 void ContactsManager::save_chat_to_database(Chat *c, ChatId chat_id) {
8797 CHECK(c != nullptr);
8798 if (c->is_being_saved) {
8799 return;
8800 }
8801 if (loaded_from_database_chats_.count(chat_id)) {
8802 save_chat_to_database_impl(c, chat_id, get_chat_database_value(c));
8803 return;
8804 }
8805 if (load_chat_from_database_queries_.count(chat_id) != 0) {
8806 return;
8807 }
8808
8809 load_chat_from_database_impl(chat_id, Auto());
8810 }
8811
save_chat_to_database_impl(Chat * c,ChatId chat_id,string value)8812 void ContactsManager::save_chat_to_database_impl(Chat *c, ChatId chat_id, string value) {
8813 CHECK(c != nullptr);
8814 CHECK(load_chat_from_database_queries_.count(chat_id) == 0);
8815 CHECK(!c->is_being_saved);
8816 c->is_being_saved = true;
8817 c->is_saved = true;
8818 LOG(INFO) << "Trying to save to database " << chat_id;
8819 G()->td_db()->get_sqlite_pmc()->set(
8820 get_chat_database_key(chat_id), std::move(value), PromiseCreator::lambda([chat_id](Result<> result) {
8821 send_closure(G()->contacts_manager(), &ContactsManager::on_save_chat_to_database, chat_id, result.is_ok());
8822 }));
8823 }
8824
on_save_chat_to_database(ChatId chat_id,bool success)8825 void ContactsManager::on_save_chat_to_database(ChatId chat_id, bool success) {
8826 if (G()->close_flag()) {
8827 return;
8828 }
8829
8830 Chat *c = get_chat(chat_id);
8831 CHECK(c != nullptr);
8832 CHECK(c->is_being_saved);
8833 CHECK(load_chat_from_database_queries_.count(chat_id) == 0);
8834 c->is_being_saved = false;
8835
8836 if (!success) {
8837 LOG(ERROR) << "Failed to save " << chat_id << " to database";
8838 c->is_saved = false;
8839 } else {
8840 LOG(INFO) << "Successfully saved " << chat_id << " to database";
8841 }
8842 if (c->is_saved) {
8843 if (c->log_event_id != 0) {
8844 binlog_erase(G()->td_db()->get_binlog(), c->log_event_id);
8845 c->log_event_id = 0;
8846 }
8847 } else {
8848 save_chat(c, chat_id, c->log_event_id != 0);
8849 }
8850 }
8851
load_chat_from_database(Chat * c,ChatId chat_id,Promise<Unit> promise)8852 void ContactsManager::load_chat_from_database(Chat *c, ChatId chat_id, Promise<Unit> promise) {
8853 if (loaded_from_database_chats_.count(chat_id)) {
8854 promise.set_value(Unit());
8855 return;
8856 }
8857
8858 CHECK(c == nullptr || !c->is_being_saved);
8859 load_chat_from_database_impl(chat_id, std::move(promise));
8860 }
8861
load_chat_from_database_impl(ChatId chat_id,Promise<Unit> promise)8862 void ContactsManager::load_chat_from_database_impl(ChatId chat_id, Promise<Unit> promise) {
8863 LOG(INFO) << "Load " << chat_id << " from database";
8864 auto &load_chat_queries = load_chat_from_database_queries_[chat_id];
8865 load_chat_queries.push_back(std::move(promise));
8866 if (load_chat_queries.size() == 1u) {
8867 G()->td_db()->get_sqlite_pmc()->get(get_chat_database_key(chat_id), PromiseCreator::lambda([chat_id](string value) {
8868 send_closure(G()->contacts_manager(),
8869 &ContactsManager::on_load_chat_from_database, chat_id,
8870 std::move(value), false);
8871 }));
8872 }
8873 }
8874
on_load_chat_from_database(ChatId chat_id,string value,bool force)8875 void ContactsManager::on_load_chat_from_database(ChatId chat_id, string value, bool force) {
8876 if (G()->close_flag() && !force) {
8877 // the chat is in Binlog and will be saved after restart
8878 return;
8879 }
8880
8881 if (!loaded_from_database_chats_.insert(chat_id).second) {
8882 return;
8883 }
8884
8885 auto it = load_chat_from_database_queries_.find(chat_id);
8886 vector<Promise<Unit>> promises;
8887 if (it != load_chat_from_database_queries_.end()) {
8888 promises = std::move(it->second);
8889 CHECK(!promises.empty());
8890 load_chat_from_database_queries_.erase(it);
8891 }
8892
8893 LOG(INFO) << "Successfully loaded " << chat_id << " of size " << value.size() << " from database";
8894 // G()->td_db()->get_sqlite_pmc()->erase(get_chat_database_key(chat_id), Auto());
8895 // return;
8896
8897 Chat *c = get_chat(chat_id);
8898 if (c == nullptr) {
8899 if (!value.empty()) {
8900 c = add_chat(chat_id);
8901
8902 log_event_parse(*c, value).ensure();
8903
8904 c->is_saved = true;
8905 update_chat(c, chat_id, true, true);
8906 }
8907 } else {
8908 CHECK(!c->is_saved); // chat can't be saved before load completes
8909 CHECK(!c->is_being_saved);
8910 auto new_value = get_chat_database_value(c);
8911 if (value != new_value) {
8912 save_chat_to_database_impl(c, chat_id, std::move(new_value));
8913 } else if (c->log_event_id != 0) {
8914 binlog_erase(G()->td_db()->get_binlog(), c->log_event_id);
8915 c->log_event_id = 0;
8916 }
8917 }
8918
8919 if (c != nullptr && c->migrated_to_channel_id.is_valid() && !have_channel_force(c->migrated_to_channel_id)) {
8920 LOG(ERROR) << "Can't find " << c->migrated_to_channel_id << " from " << chat_id;
8921 }
8922
8923 for (auto &promise : promises) {
8924 promise.set_value(Unit());
8925 }
8926 }
8927
have_chat_force(ChatId chat_id)8928 bool ContactsManager::have_chat_force(ChatId chat_id) {
8929 return get_chat_force(chat_id) != nullptr;
8930 }
8931
get_chat_force(ChatId chat_id)8932 ContactsManager::Chat *ContactsManager::get_chat_force(ChatId chat_id) {
8933 if (!chat_id.is_valid()) {
8934 return nullptr;
8935 }
8936
8937 Chat *c = get_chat(chat_id);
8938 if (c != nullptr) {
8939 if (c->migrated_to_channel_id.is_valid() && !have_channel_force(c->migrated_to_channel_id)) {
8940 LOG(ERROR) << "Can't find " << c->migrated_to_channel_id << " from " << chat_id;
8941 }
8942
8943 return c;
8944 }
8945 if (!G()->parameters().use_chat_info_db) {
8946 return nullptr;
8947 }
8948 if (loaded_from_database_chats_.count(chat_id)) {
8949 return nullptr;
8950 }
8951
8952 LOG(INFO) << "Trying to load " << chat_id << " from database";
8953 on_load_chat_from_database(chat_id, G()->td_db()->get_sqlite_sync_pmc()->get(get_chat_database_key(chat_id)), true);
8954 return get_chat(chat_id);
8955 }
8956
8957 class ContactsManager::ChannelLogEvent {
8958 public:
8959 ChannelId channel_id;
8960 Channel c;
8961
8962 ChannelLogEvent() = default;
8963
ChannelLogEvent(ChannelId channel_id,const Channel & c)8964 ChannelLogEvent(ChannelId channel_id, const Channel &c) : channel_id(channel_id), c(c) {
8965 }
8966
8967 template <class StorerT>
store(StorerT & storer) const8968 void store(StorerT &storer) const {
8969 td::store(channel_id, storer);
8970 td::store(c, storer);
8971 }
8972
8973 template <class ParserT>
parse(ParserT & parser)8974 void parse(ParserT &parser) {
8975 td::parse(channel_id, parser);
8976 td::parse(c, parser);
8977 }
8978 };
8979
save_channel(Channel * c,ChannelId channel_id,bool from_binlog)8980 void ContactsManager::save_channel(Channel *c, ChannelId channel_id, bool from_binlog) {
8981 if (!G()->parameters().use_chat_info_db) {
8982 return;
8983 }
8984 CHECK(c != nullptr);
8985 if (!c->is_saved) {
8986 if (!from_binlog) {
8987 auto log_event = ChannelLogEvent(channel_id, *c);
8988 auto storer = get_log_event_storer(log_event);
8989 if (c->log_event_id == 0) {
8990 c->log_event_id = binlog_add(G()->td_db()->get_binlog(), LogEvent::HandlerType::Channels, storer);
8991 } else {
8992 binlog_rewrite(G()->td_db()->get_binlog(), c->log_event_id, LogEvent::HandlerType::Channels, storer);
8993 }
8994 }
8995
8996 save_channel_to_database(c, channel_id);
8997 return;
8998 }
8999 }
9000
on_binlog_channel_event(BinlogEvent && event)9001 void ContactsManager::on_binlog_channel_event(BinlogEvent &&event) {
9002 if (!G()->parameters().use_chat_info_db) {
9003 binlog_erase(G()->td_db()->get_binlog(), event.id_);
9004 return;
9005 }
9006
9007 ChannelLogEvent log_event;
9008 log_event_parse(log_event, event.data_).ensure();
9009
9010 auto channel_id = log_event.channel_id;
9011 if (have_channel(channel_id)) {
9012 LOG(ERROR) << "Skip adding already added " << channel_id;
9013 binlog_erase(G()->td_db()->get_binlog(), event.id_);
9014 return;
9015 }
9016
9017 LOG(INFO) << "Add " << channel_id << " from binlog";
9018 Channel *c = add_channel(channel_id, "on_binlog_channel_event");
9019 *c = std::move(log_event.c); // channels come from binlog before all other events, so just add them
9020
9021 c->log_event_id = event.id_;
9022
9023 update_channel(c, channel_id, true, false);
9024 }
9025
get_channel_database_key(ChannelId channel_id)9026 string ContactsManager::get_channel_database_key(ChannelId channel_id) {
9027 return PSTRING() << "ch" << channel_id.get();
9028 }
9029
get_channel_database_value(const Channel * c)9030 string ContactsManager::get_channel_database_value(const Channel *c) {
9031 return log_event_store(*c).as_slice().str();
9032 }
9033
save_channel_to_database(Channel * c,ChannelId channel_id)9034 void ContactsManager::save_channel_to_database(Channel *c, ChannelId channel_id) {
9035 CHECK(c != nullptr);
9036 if (c->is_being_saved) {
9037 return;
9038 }
9039 if (loaded_from_database_channels_.count(channel_id)) {
9040 save_channel_to_database_impl(c, channel_id, get_channel_database_value(c));
9041 return;
9042 }
9043 if (load_channel_from_database_queries_.count(channel_id) != 0) {
9044 return;
9045 }
9046
9047 load_channel_from_database_impl(channel_id, Auto());
9048 }
9049
save_channel_to_database_impl(Channel * c,ChannelId channel_id,string value)9050 void ContactsManager::save_channel_to_database_impl(Channel *c, ChannelId channel_id, string value) {
9051 CHECK(c != nullptr);
9052 CHECK(load_channel_from_database_queries_.count(channel_id) == 0);
9053 CHECK(!c->is_being_saved);
9054 c->is_being_saved = true;
9055 c->is_saved = true;
9056 LOG(INFO) << "Trying to save to database " << channel_id;
9057 G()->td_db()->get_sqlite_pmc()->set(
9058 get_channel_database_key(channel_id), std::move(value), PromiseCreator::lambda([channel_id](Result<> result) {
9059 send_closure(G()->contacts_manager(), &ContactsManager::on_save_channel_to_database, channel_id,
9060 result.is_ok());
9061 }));
9062 }
9063
on_save_channel_to_database(ChannelId channel_id,bool success)9064 void ContactsManager::on_save_channel_to_database(ChannelId channel_id, bool success) {
9065 if (G()->close_flag()) {
9066 return;
9067 }
9068
9069 Channel *c = get_channel(channel_id);
9070 CHECK(c != nullptr);
9071 CHECK(c->is_being_saved);
9072 CHECK(load_channel_from_database_queries_.count(channel_id) == 0);
9073 c->is_being_saved = false;
9074
9075 if (!success) {
9076 LOG(ERROR) << "Failed to save " << channel_id << " to database";
9077 c->is_saved = false;
9078 } else {
9079 LOG(INFO) << "Successfully saved " << channel_id << " to database";
9080 }
9081 if (c->is_saved) {
9082 if (c->log_event_id != 0) {
9083 binlog_erase(G()->td_db()->get_binlog(), c->log_event_id);
9084 c->log_event_id = 0;
9085 }
9086 } else {
9087 save_channel(c, channel_id, c->log_event_id != 0);
9088 }
9089 }
9090
load_channel_from_database(Channel * c,ChannelId channel_id,Promise<Unit> promise)9091 void ContactsManager::load_channel_from_database(Channel *c, ChannelId channel_id, Promise<Unit> promise) {
9092 if (loaded_from_database_channels_.count(channel_id)) {
9093 promise.set_value(Unit());
9094 return;
9095 }
9096
9097 CHECK(c == nullptr || !c->is_being_saved);
9098 load_channel_from_database_impl(channel_id, std::move(promise));
9099 }
9100
load_channel_from_database_impl(ChannelId channel_id,Promise<Unit> promise)9101 void ContactsManager::load_channel_from_database_impl(ChannelId channel_id, Promise<Unit> promise) {
9102 LOG(INFO) << "Load " << channel_id << " from database";
9103 auto &load_channel_queries = load_channel_from_database_queries_[channel_id];
9104 load_channel_queries.push_back(std::move(promise));
9105 if (load_channel_queries.size() == 1u) {
9106 G()->td_db()->get_sqlite_pmc()->get(
9107 get_channel_database_key(channel_id), PromiseCreator::lambda([channel_id](string value) {
9108 send_closure(G()->contacts_manager(), &ContactsManager::on_load_channel_from_database, channel_id,
9109 std::move(value), false);
9110 }));
9111 }
9112 }
9113
on_load_channel_from_database(ChannelId channel_id,string value,bool force)9114 void ContactsManager::on_load_channel_from_database(ChannelId channel_id, string value, bool force) {
9115 if (G()->close_flag() && !force) {
9116 // the channel is in Binlog and will be saved after restart
9117 return;
9118 }
9119
9120 if (!loaded_from_database_channels_.insert(channel_id).second) {
9121 return;
9122 }
9123
9124 auto it = load_channel_from_database_queries_.find(channel_id);
9125 vector<Promise<Unit>> promises;
9126 if (it != load_channel_from_database_queries_.end()) {
9127 promises = std::move(it->second);
9128 CHECK(!promises.empty());
9129 load_channel_from_database_queries_.erase(it);
9130 }
9131
9132 LOG(INFO) << "Successfully loaded " << channel_id << " of size " << value.size() << " from database";
9133 // G()->td_db()->get_sqlite_pmc()->erase(get_channel_database_key(channel_id), Auto());
9134 // return;
9135
9136 Channel *c = get_channel(channel_id);
9137 if (c == nullptr) {
9138 if (!value.empty()) {
9139 c = add_channel(channel_id, "on_load_channel_from_database");
9140
9141 log_event_parse(*c, value).ensure();
9142
9143 c->is_saved = true;
9144 update_channel(c, channel_id, true, true);
9145 }
9146 } else {
9147 CHECK(!c->is_saved); // channel can't be saved before load completes
9148 CHECK(!c->is_being_saved);
9149 if (!value.empty()) {
9150 Channel temp_c;
9151 log_event_parse(temp_c, value).ensure();
9152 if (c->participant_count == 0 && temp_c.participant_count != 0) {
9153 c->participant_count = temp_c.participant_count;
9154 CHECK(c->is_update_supergroup_sent);
9155 send_closure(G()->td(), &Td::send_update,
9156 make_tl_object<td_api::updateSupergroup>(get_supergroup_object(channel_id, c)));
9157 }
9158
9159 c->status.update_restrictions();
9160 temp_c.status.update_restrictions();
9161 if (temp_c.status != c->status) {
9162 on_channel_status_changed(c, channel_id, temp_c.status, c->status);
9163 CHECK(!c->is_being_saved);
9164 }
9165
9166 if (temp_c.username != c->username) {
9167 on_channel_username_changed(c, channel_id, temp_c.username, c->username);
9168 CHECK(!c->is_being_saved);
9169 }
9170 }
9171 auto new_value = get_channel_database_value(c);
9172 if (value != new_value) {
9173 save_channel_to_database_impl(c, channel_id, std::move(new_value));
9174 } else if (c->log_event_id != 0) {
9175 binlog_erase(G()->td_db()->get_binlog(), c->log_event_id);
9176 c->log_event_id = 0;
9177 }
9178 }
9179
9180 for (auto &promise : promises) {
9181 promise.set_value(Unit());
9182 }
9183 }
9184
have_channel_force(ChannelId channel_id)9185 bool ContactsManager::have_channel_force(ChannelId channel_id) {
9186 return get_channel_force(channel_id) != nullptr;
9187 }
9188
get_channel_force(ChannelId channel_id)9189 ContactsManager::Channel *ContactsManager::get_channel_force(ChannelId channel_id) {
9190 if (!channel_id.is_valid()) {
9191 return nullptr;
9192 }
9193
9194 Channel *c = get_channel(channel_id);
9195 if (c != nullptr) {
9196 return c;
9197 }
9198 if (!G()->parameters().use_chat_info_db) {
9199 return nullptr;
9200 }
9201 if (loaded_from_database_channels_.count(channel_id)) {
9202 return nullptr;
9203 }
9204
9205 LOG(INFO) << "Trying to load " << channel_id << " from database";
9206 on_load_channel_from_database(channel_id,
9207 G()->td_db()->get_sqlite_sync_pmc()->get(get_channel_database_key(channel_id)), true);
9208 return get_channel(channel_id);
9209 }
9210
9211 class ContactsManager::SecretChatLogEvent {
9212 public:
9213 SecretChatId secret_chat_id;
9214 SecretChat c;
9215
9216 SecretChatLogEvent() = default;
9217
SecretChatLogEvent(SecretChatId secret_chat_id,const SecretChat & c)9218 SecretChatLogEvent(SecretChatId secret_chat_id, const SecretChat &c) : secret_chat_id(secret_chat_id), c(c) {
9219 }
9220
9221 template <class StorerT>
store(StorerT & storer) const9222 void store(StorerT &storer) const {
9223 td::store(secret_chat_id, storer);
9224 td::store(c, storer);
9225 }
9226
9227 template <class ParserT>
parse(ParserT & parser)9228 void parse(ParserT &parser) {
9229 td::parse(secret_chat_id, parser);
9230 td::parse(c, parser);
9231 }
9232 };
9233
save_secret_chat(SecretChat * c,SecretChatId secret_chat_id,bool from_binlog)9234 void ContactsManager::save_secret_chat(SecretChat *c, SecretChatId secret_chat_id, bool from_binlog) {
9235 if (!G()->parameters().use_chat_info_db) {
9236 return;
9237 }
9238 CHECK(c != nullptr);
9239 if (!c->is_saved) {
9240 if (!from_binlog) {
9241 auto log_event = SecretChatLogEvent(secret_chat_id, *c);
9242 auto storer = get_log_event_storer(log_event);
9243 if (c->log_event_id == 0) {
9244 c->log_event_id = binlog_add(G()->td_db()->get_binlog(), LogEvent::HandlerType::SecretChatInfos, storer);
9245 } else {
9246 binlog_rewrite(G()->td_db()->get_binlog(), c->log_event_id, LogEvent::HandlerType::SecretChatInfos, storer);
9247 }
9248 }
9249
9250 save_secret_chat_to_database(c, secret_chat_id);
9251 return;
9252 }
9253 }
9254
on_binlog_secret_chat_event(BinlogEvent && event)9255 void ContactsManager::on_binlog_secret_chat_event(BinlogEvent &&event) {
9256 if (!G()->parameters().use_chat_info_db) {
9257 binlog_erase(G()->td_db()->get_binlog(), event.id_);
9258 return;
9259 }
9260
9261 SecretChatLogEvent log_event;
9262 log_event_parse(log_event, event.data_).ensure();
9263
9264 auto secret_chat_id = log_event.secret_chat_id;
9265 if (have_secret_chat(secret_chat_id)) {
9266 LOG(ERROR) << "Skip adding already added " << secret_chat_id;
9267 binlog_erase(G()->td_db()->get_binlog(), event.id_);
9268 return;
9269 }
9270
9271 LOG(INFO) << "Add " << secret_chat_id << " from binlog";
9272 SecretChat *c = add_secret_chat(secret_chat_id);
9273 *c = std::move(log_event.c); // secret chats come from binlog before all other events, so just add them
9274
9275 c->log_event_id = event.id_;
9276
9277 update_secret_chat(c, secret_chat_id, true, false);
9278 }
9279
get_secret_chat_database_key(SecretChatId secret_chat_id)9280 string ContactsManager::get_secret_chat_database_key(SecretChatId secret_chat_id) {
9281 return PSTRING() << "sc" << secret_chat_id.get();
9282 }
9283
get_secret_chat_database_value(const SecretChat * c)9284 string ContactsManager::get_secret_chat_database_value(const SecretChat *c) {
9285 return log_event_store(*c).as_slice().str();
9286 }
9287
save_secret_chat_to_database(SecretChat * c,SecretChatId secret_chat_id)9288 void ContactsManager::save_secret_chat_to_database(SecretChat *c, SecretChatId secret_chat_id) {
9289 CHECK(c != nullptr);
9290 if (c->is_being_saved) {
9291 return;
9292 }
9293 if (loaded_from_database_secret_chats_.count(secret_chat_id)) {
9294 save_secret_chat_to_database_impl(c, secret_chat_id, get_secret_chat_database_value(c));
9295 return;
9296 }
9297 if (load_secret_chat_from_database_queries_.count(secret_chat_id) != 0) {
9298 return;
9299 }
9300
9301 load_secret_chat_from_database_impl(secret_chat_id, Auto());
9302 }
9303
save_secret_chat_to_database_impl(SecretChat * c,SecretChatId secret_chat_id,string value)9304 void ContactsManager::save_secret_chat_to_database_impl(SecretChat *c, SecretChatId secret_chat_id, string value) {
9305 CHECK(c != nullptr);
9306 CHECK(load_secret_chat_from_database_queries_.count(secret_chat_id) == 0);
9307 CHECK(!c->is_being_saved);
9308 c->is_being_saved = true;
9309 c->is_saved = true;
9310 LOG(INFO) << "Trying to save to database " << secret_chat_id;
9311 G()->td_db()->get_sqlite_pmc()->set(get_secret_chat_database_key(secret_chat_id), std::move(value),
9312 PromiseCreator::lambda([secret_chat_id](Result<> result) {
9313 send_closure(G()->contacts_manager(),
9314 &ContactsManager::on_save_secret_chat_to_database, secret_chat_id,
9315 result.is_ok());
9316 }));
9317 }
9318
on_save_secret_chat_to_database(SecretChatId secret_chat_id,bool success)9319 void ContactsManager::on_save_secret_chat_to_database(SecretChatId secret_chat_id, bool success) {
9320 if (G()->close_flag()) {
9321 return;
9322 }
9323
9324 SecretChat *c = get_secret_chat(secret_chat_id);
9325 CHECK(c != nullptr);
9326 CHECK(c->is_being_saved);
9327 CHECK(load_secret_chat_from_database_queries_.count(secret_chat_id) == 0);
9328 c->is_being_saved = false;
9329
9330 if (!success) {
9331 LOG(ERROR) << "Failed to save " << secret_chat_id << " to database";
9332 c->is_saved = false;
9333 } else {
9334 LOG(INFO) << "Successfully saved " << secret_chat_id << " to database";
9335 }
9336 if (c->is_saved) {
9337 if (c->log_event_id != 0) {
9338 binlog_erase(G()->td_db()->get_binlog(), c->log_event_id);
9339 c->log_event_id = 0;
9340 }
9341 } else {
9342 save_secret_chat(c, secret_chat_id, c->log_event_id != 0);
9343 }
9344 }
9345
load_secret_chat_from_database(SecretChat * c,SecretChatId secret_chat_id,Promise<Unit> promise)9346 void ContactsManager::load_secret_chat_from_database(SecretChat *c, SecretChatId secret_chat_id,
9347 Promise<Unit> promise) {
9348 if (loaded_from_database_secret_chats_.count(secret_chat_id)) {
9349 promise.set_value(Unit());
9350 return;
9351 }
9352
9353 CHECK(c == nullptr || !c->is_being_saved);
9354 load_secret_chat_from_database_impl(secret_chat_id, std::move(promise));
9355 }
9356
load_secret_chat_from_database_impl(SecretChatId secret_chat_id,Promise<Unit> promise)9357 void ContactsManager::load_secret_chat_from_database_impl(SecretChatId secret_chat_id, Promise<Unit> promise) {
9358 LOG(INFO) << "Load " << secret_chat_id << " from database";
9359 auto &load_secret_chat_queries = load_secret_chat_from_database_queries_[secret_chat_id];
9360 load_secret_chat_queries.push_back(std::move(promise));
9361 if (load_secret_chat_queries.size() == 1u) {
9362 G()->td_db()->get_sqlite_pmc()->get(
9363 get_secret_chat_database_key(secret_chat_id), PromiseCreator::lambda([secret_chat_id](string value) {
9364 send_closure(G()->contacts_manager(), &ContactsManager::on_load_secret_chat_from_database, secret_chat_id,
9365 std::move(value), false);
9366 }));
9367 }
9368 }
9369
on_load_secret_chat_from_database(SecretChatId secret_chat_id,string value,bool force)9370 void ContactsManager::on_load_secret_chat_from_database(SecretChatId secret_chat_id, string value, bool force) {
9371 if (G()->close_flag() && !force) {
9372 // the secret chat is in Binlog and will be saved after restart
9373 return;
9374 }
9375
9376 if (!loaded_from_database_secret_chats_.insert(secret_chat_id).second) {
9377 return;
9378 }
9379
9380 auto it = load_secret_chat_from_database_queries_.find(secret_chat_id);
9381 vector<Promise<Unit>> promises;
9382 if (it != load_secret_chat_from_database_queries_.end()) {
9383 promises = std::move(it->second);
9384 CHECK(!promises.empty());
9385 load_secret_chat_from_database_queries_.erase(it);
9386 }
9387
9388 LOG(INFO) << "Successfully loaded " << secret_chat_id << " of size " << value.size() << " from database";
9389 // G()->td_db()->get_sqlite_pmc()->erase(get_secret_chat_database_key(secret_chat_id), Auto());
9390 // return;
9391
9392 SecretChat *c = get_secret_chat(secret_chat_id);
9393 if (c == nullptr) {
9394 if (!value.empty()) {
9395 c = add_secret_chat(secret_chat_id);
9396
9397 log_event_parse(*c, value).ensure();
9398
9399 c->is_saved = true;
9400 update_secret_chat(c, secret_chat_id, true, true);
9401 }
9402 } else {
9403 CHECK(!c->is_saved); // secret chat can't be saved before load completes
9404 CHECK(!c->is_being_saved);
9405 auto new_value = get_secret_chat_database_value(c);
9406 if (value != new_value) {
9407 save_secret_chat_to_database_impl(c, secret_chat_id, std::move(new_value));
9408 } else if (c->log_event_id != 0) {
9409 binlog_erase(G()->td_db()->get_binlog(), c->log_event_id);
9410 c->log_event_id = 0;
9411 }
9412 }
9413
9414 // TODO load users asynchronously
9415 if (c != nullptr && !have_user_force(c->user_id)) {
9416 LOG(ERROR) << "Can't find " << c->user_id << " from " << secret_chat_id;
9417 }
9418
9419 for (auto &promise : promises) {
9420 promise.set_value(Unit());
9421 }
9422 }
9423
have_secret_chat_force(SecretChatId secret_chat_id)9424 bool ContactsManager::have_secret_chat_force(SecretChatId secret_chat_id) {
9425 return get_secret_chat_force(secret_chat_id) != nullptr;
9426 }
9427
get_secret_chat_force(SecretChatId secret_chat_id)9428 ContactsManager::SecretChat *ContactsManager::get_secret_chat_force(SecretChatId secret_chat_id) {
9429 if (!secret_chat_id.is_valid()) {
9430 return nullptr;
9431 }
9432
9433 SecretChat *c = get_secret_chat(secret_chat_id);
9434 if (c != nullptr) {
9435 if (!have_user_force(c->user_id)) {
9436 LOG(ERROR) << "Can't find " << c->user_id << " from " << secret_chat_id;
9437 }
9438 return c;
9439 }
9440 if (!G()->parameters().use_chat_info_db) {
9441 return nullptr;
9442 }
9443 if (loaded_from_database_secret_chats_.count(secret_chat_id)) {
9444 return nullptr;
9445 }
9446
9447 LOG(INFO) << "Trying to load " << secret_chat_id << " from database";
9448 on_load_secret_chat_from_database(
9449 secret_chat_id, G()->td_db()->get_sqlite_sync_pmc()->get(get_secret_chat_database_key(secret_chat_id)), true);
9450 return get_secret_chat(secret_chat_id);
9451 }
9452
save_user_full(const UserFull * user_full,UserId user_id)9453 void ContactsManager::save_user_full(const UserFull *user_full, UserId user_id) {
9454 if (!G()->parameters().use_chat_info_db) {
9455 return;
9456 }
9457
9458 LOG(INFO) << "Trying to save to database full " << user_id;
9459 CHECK(user_full != nullptr);
9460 G()->td_db()->get_sqlite_pmc()->set(get_user_full_database_key(user_id), get_user_full_database_value(user_full),
9461 Auto());
9462 }
9463
get_user_full_database_key(UserId user_id)9464 string ContactsManager::get_user_full_database_key(UserId user_id) {
9465 return PSTRING() << "usf" << user_id.get();
9466 }
9467
get_user_full_database_value(const UserFull * user_full)9468 string ContactsManager::get_user_full_database_value(const UserFull *user_full) {
9469 return log_event_store(*user_full).as_slice().str();
9470 }
9471
on_load_user_full_from_database(UserId user_id,string value)9472 void ContactsManager::on_load_user_full_from_database(UserId user_id, string value) {
9473 LOG(INFO) << "Successfully loaded full " << user_id << " of size " << value.size() << " from database";
9474 // G()->td_db()->get_sqlite_pmc()->erase(get_user_full_database_key(user_id), Auto());
9475 // return;
9476
9477 if (get_user_full(user_id) != nullptr || value.empty()) {
9478 return;
9479 }
9480
9481 UserFull *user_full = add_user_full(user_id);
9482 auto status = log_event_parse(*user_full, value);
9483 if (status.is_error()) {
9484 // can't happen unless database is broken
9485 LOG(ERROR) << "Repair broken full " << user_id << ' ' << format::as_hex_dump<4>(Slice(value));
9486
9487 // just clean all known data about the user and pretend that there was nothing in the database
9488 users_full_.erase(user_id);
9489 G()->td_db()->get_sqlite_pmc()->erase(get_user_full_database_key(user_id), Auto());
9490 return;
9491 }
9492
9493 Dependencies dependencies;
9494 dependencies.user_ids.insert(user_id);
9495 if (!resolve_dependencies_force(td_, dependencies, "on_load_user_full_from_database")) {
9496 users_full_.erase(user_id);
9497 G()->td_db()->get_sqlite_pmc()->erase(get_user_full_database_key(user_id), Auto());
9498 return;
9499 }
9500
9501 if (user_full->need_phone_number_privacy_exception && is_user_contact(user_id)) {
9502 user_full->need_phone_number_privacy_exception = false;
9503 }
9504
9505 User *u = get_user(user_id);
9506 CHECK(u != nullptr);
9507 if (u->photo.id != user_full->photo.id.get()) {
9508 user_full->photo = Photo();
9509 if (u->photo.id > 0) {
9510 user_full->expires_at = 0.0;
9511 }
9512 }
9513 if (!user_full->photo.is_empty()) {
9514 register_user_photo(u, user_id, user_full->photo);
9515 }
9516
9517 td_->group_call_manager_->on_update_dialog_about(DialogId(user_id), user_full->about, false);
9518
9519 user_full->is_update_user_full_sent = true;
9520 update_user_full(user_full, user_id, "on_load_user_full_from_database", true);
9521
9522 if (is_user_deleted(user_id)) {
9523 drop_user_full(user_id);
9524 } else if (user_full->expires_at == 0.0) {
9525 load_user_full(user_id, true, Auto(), "on_load_user_full_from_database");
9526 }
9527 }
9528
get_user_full_force(UserId user_id)9529 ContactsManager::UserFull *ContactsManager::get_user_full_force(UserId user_id) {
9530 if (!have_user_force(user_id)) {
9531 return nullptr;
9532 }
9533
9534 UserFull *user_full = get_user_full(user_id);
9535 if (user_full != nullptr) {
9536 return user_full;
9537 }
9538 if (!G()->parameters().use_chat_info_db) {
9539 return nullptr;
9540 }
9541 if (!unavailable_user_fulls_.insert(user_id).second) {
9542 return nullptr;
9543 }
9544
9545 LOG(INFO) << "Trying to load full " << user_id << " from database";
9546 on_load_user_full_from_database(user_id,
9547 G()->td_db()->get_sqlite_sync_pmc()->get(get_user_full_database_key(user_id)));
9548 return get_user_full(user_id);
9549 }
9550
save_chat_full(const ChatFull * chat_full,ChatId chat_id)9551 void ContactsManager::save_chat_full(const ChatFull *chat_full, ChatId chat_id) {
9552 if (!G()->parameters().use_chat_info_db) {
9553 return;
9554 }
9555
9556 LOG(INFO) << "Trying to save to database full " << chat_id;
9557 CHECK(chat_full != nullptr);
9558 G()->td_db()->get_sqlite_pmc()->set(get_chat_full_database_key(chat_id), get_chat_full_database_value(chat_full),
9559 Auto());
9560 }
9561
get_chat_full_database_key(ChatId chat_id)9562 string ContactsManager::get_chat_full_database_key(ChatId chat_id) {
9563 return PSTRING() << "grf" << chat_id.get();
9564 }
9565
get_chat_full_database_value(const ChatFull * chat_full)9566 string ContactsManager::get_chat_full_database_value(const ChatFull *chat_full) {
9567 return log_event_store(*chat_full).as_slice().str();
9568 }
9569
on_load_chat_full_from_database(ChatId chat_id,string value)9570 void ContactsManager::on_load_chat_full_from_database(ChatId chat_id, string value) {
9571 LOG(INFO) << "Successfully loaded full " << chat_id << " of size " << value.size() << " from database";
9572 // G()->td_db()->get_sqlite_pmc()->erase(get_chat_full_database_key(chat_id), Auto());
9573 // return;
9574
9575 if (get_chat_full(chat_id) != nullptr || value.empty()) {
9576 return;
9577 }
9578
9579 ChatFull *chat_full = add_chat_full(chat_id);
9580 auto status = log_event_parse(*chat_full, value);
9581 if (status.is_error()) {
9582 // can't happen unless database is broken
9583 LOG(ERROR) << "Repair broken full " << chat_id << ' ' << format::as_hex_dump<4>(Slice(value));
9584
9585 // just clean all known data about the chat and pretend that there was nothing in the database
9586 chats_full_.erase(chat_id);
9587 G()->td_db()->get_sqlite_pmc()->erase(get_chat_full_database_key(chat_id), Auto());
9588 return;
9589 }
9590
9591 Dependencies dependencies;
9592 dependencies.chat_ids.insert(chat_id);
9593 dependencies.user_ids.insert(chat_full->creator_user_id);
9594 for (auto &participant : chat_full->participants) {
9595 add_message_sender_dependencies(dependencies, participant.dialog_id_);
9596 dependencies.user_ids.insert(participant.inviter_user_id_);
9597 }
9598 dependencies.user_ids.insert(chat_full->invite_link.get_creator_user_id());
9599 if (!resolve_dependencies_force(td_, dependencies, "on_load_chat_full_from_database")) {
9600 chats_full_.erase(chat_id);
9601 G()->td_db()->get_sqlite_pmc()->erase(get_chat_full_database_key(chat_id), Auto());
9602 return;
9603 }
9604
9605 Chat *c = get_chat(chat_id);
9606 CHECK(c != nullptr);
9607
9608 bool need_invite_link = c->is_active && c->status.can_manage_invite_links();
9609 bool have_invite_link = chat_full->invite_link.is_valid();
9610 if (need_invite_link != have_invite_link) {
9611 if (need_invite_link) {
9612 // ignore ChatFull without invite link
9613 chats_full_.erase(chat_id);
9614 return;
9615 } else {
9616 chat_full->invite_link = DialogInviteLink();
9617 }
9618 }
9619
9620 if (td_->file_manager_->get_file_view(c->photo.small_file_id).get_unique_file_id() !=
9621 td_->file_manager_->get_file_view(as_fake_dialog_photo(chat_full->photo, DialogId(chat_id)).small_file_id)
9622 .get_unique_file_id()) {
9623 chat_full->photo = Photo();
9624 if (c->photo.small_file_id.is_valid()) {
9625 reload_chat_full(chat_id, Auto());
9626 }
9627 }
9628
9629 td_->group_call_manager_->on_update_dialog_about(DialogId(chat_id), chat_full->description, false);
9630
9631 on_update_chat_full_photo(chat_full, chat_id, std::move(chat_full->photo));
9632
9633 chat_full->is_update_chat_full_sent = true;
9634 update_chat_full(chat_full, chat_id, "on_load_chat_full_from_database", true);
9635 }
9636
get_chat_full_force(ChatId chat_id,const char * source)9637 ContactsManager::ChatFull *ContactsManager::get_chat_full_force(ChatId chat_id, const char *source) {
9638 if (!have_chat_force(chat_id)) {
9639 return nullptr;
9640 }
9641
9642 ChatFull *chat_full = get_chat_full(chat_id);
9643 if (chat_full != nullptr) {
9644 return chat_full;
9645 }
9646 if (!G()->parameters().use_chat_info_db) {
9647 return nullptr;
9648 }
9649 if (!unavailable_chat_fulls_.insert(chat_id).second) {
9650 return nullptr;
9651 }
9652
9653 LOG(INFO) << "Trying to load full " << chat_id << " from database from " << source;
9654 on_load_chat_full_from_database(chat_id,
9655 G()->td_db()->get_sqlite_sync_pmc()->get(get_chat_full_database_key(chat_id)));
9656 return get_chat_full(chat_id);
9657 }
9658
save_channel_full(const ChannelFull * channel_full,ChannelId channel_id)9659 void ContactsManager::save_channel_full(const ChannelFull *channel_full, ChannelId channel_id) {
9660 if (!G()->parameters().use_chat_info_db) {
9661 return;
9662 }
9663
9664 LOG(INFO) << "Trying to save to database full " << channel_id;
9665 CHECK(channel_full != nullptr);
9666 G()->td_db()->get_sqlite_pmc()->set(get_channel_full_database_key(channel_id),
9667 get_channel_full_database_value(channel_full), Auto());
9668 }
9669
get_channel_full_database_key(ChannelId channel_id)9670 string ContactsManager::get_channel_full_database_key(ChannelId channel_id) {
9671 return PSTRING() << "chf" << channel_id.get();
9672 }
9673
get_channel_full_database_value(const ChannelFull * channel_full)9674 string ContactsManager::get_channel_full_database_value(const ChannelFull *channel_full) {
9675 return log_event_store(*channel_full).as_slice().str();
9676 }
9677
on_load_channel_full_from_database(ChannelId channel_id,string value,const char * source)9678 void ContactsManager::on_load_channel_full_from_database(ChannelId channel_id, string value, const char *source) {
9679 LOG(INFO) << "Successfully loaded full " << channel_id << " of size " << value.size() << " from database from "
9680 << source;
9681 // G()->td_db()->get_sqlite_pmc()->erase(get_channel_full_database_key(channel_id), Auto());
9682 // return;
9683
9684 if (get_channel_full(channel_id, true, "on_load_channel_full_from_database") != nullptr || value.empty()) {
9685 return;
9686 }
9687
9688 ChannelFull *channel_full = add_channel_full(channel_id);
9689 auto status = log_event_parse(*channel_full, value);
9690 if (status.is_error()) {
9691 // can't happen unless database is broken
9692 LOG(ERROR) << "Repair broken full " << channel_id << ' ' << format::as_hex_dump<4>(Slice(value));
9693
9694 // just clean all known data about the channel and pretend that there was nothing in the database
9695 channels_full_.erase(channel_id);
9696 G()->td_db()->get_sqlite_pmc()->erase(get_channel_full_database_key(channel_id), Auto());
9697 return;
9698 }
9699
9700 Dependencies dependencies;
9701 dependencies.channel_ids.insert(channel_id);
9702 // must not depend on the linked_dialog_id itself, because message database can be disabled
9703 // the Dialog will be forcely created in update_channel_full
9704 add_dialog_dependencies(dependencies, DialogId(channel_full->linked_channel_id));
9705 dependencies.chat_ids.insert(channel_full->migrated_from_chat_id);
9706 dependencies.user_ids.insert(channel_full->bot_user_ids.begin(), channel_full->bot_user_ids.end());
9707 dependencies.user_ids.insert(channel_full->invite_link.get_creator_user_id());
9708 if (!resolve_dependencies_force(td_, dependencies, source)) {
9709 channels_full_.erase(channel_id);
9710 G()->td_db()->get_sqlite_pmc()->erase(get_channel_full_database_key(channel_id), Auto());
9711 return;
9712 }
9713
9714 Channel *c = get_channel(channel_id);
9715 CHECK(c != nullptr);
9716
9717 bool need_invite_link = c->status.can_manage_invite_links();
9718 bool have_invite_link = channel_full->invite_link.is_valid();
9719 if (need_invite_link != have_invite_link) {
9720 if (need_invite_link) {
9721 // ignore ChannelFull without invite link
9722 channels_full_.erase(channel_id);
9723 return;
9724 } else {
9725 channel_full->invite_link = DialogInviteLink();
9726 }
9727 }
9728
9729 if (td_->file_manager_->get_file_view(c->photo.small_file_id).get_unique_file_id() !=
9730 td_->file_manager_->get_file_view(as_fake_dialog_photo(channel_full->photo, DialogId(channel_id)).small_file_id)
9731 .get_unique_file_id()) {
9732 channel_full->photo = Photo();
9733 if (c->photo.small_file_id.is_valid()) {
9734 channel_full->expires_at = 0.0;
9735 }
9736 }
9737 auto photo = std::move(channel_full->photo);
9738 on_update_channel_full_photo(channel_full, channel_id, std::move(photo));
9739
9740 if (channel_full->participant_count < channel_full->administrator_count) {
9741 channel_full->participant_count = channel_full->administrator_count;
9742 }
9743 if (c->participant_count != 0 && c->participant_count != channel_full->participant_count) {
9744 channel_full->participant_count = c->participant_count;
9745
9746 if (channel_full->participant_count < channel_full->administrator_count) {
9747 channel_full->participant_count = channel_full->administrator_count;
9748 channel_full->expires_at = 0.0;
9749
9750 c->participant_count = channel_full->participant_count;
9751 c->is_changed = true;
9752 update_channel(c, channel_id);
9753 }
9754 }
9755
9756 if (invalidated_channels_full_.erase(channel_id) > 0 ||
9757 (!c->is_slow_mode_enabled && channel_full->slow_mode_delay != 0)) {
9758 do_invalidate_channel_full(channel_full, channel_id, !c->is_slow_mode_enabled);
9759 }
9760
9761 td_->group_call_manager_->on_update_dialog_about(DialogId(channel_id), channel_full->description, false);
9762
9763 send_closure_later(G()->messages_manager(), &MessagesManager::on_dialog_bots_updated, DialogId(channel_id),
9764 channel_full->bot_user_ids, true);
9765
9766 channel_full->is_update_channel_full_sent = true;
9767 update_channel_full(channel_full, channel_id, "on_load_channel_full_from_database", true);
9768
9769 if (channel_full->expires_at == 0.0) {
9770 load_channel_full(channel_id, true, Auto(), "on_load_channel_full_from_database");
9771 }
9772 }
9773
get_channel_full_force(ChannelId channel_id,bool only_local,const char * source)9774 ContactsManager::ChannelFull *ContactsManager::get_channel_full_force(ChannelId channel_id, bool only_local,
9775 const char *source) {
9776 if (!have_channel_force(channel_id)) {
9777 return nullptr;
9778 }
9779
9780 ChannelFull *channel_full = get_channel_full(channel_id, only_local, source);
9781 if (channel_full != nullptr) {
9782 return channel_full;
9783 }
9784 if (!G()->parameters().use_chat_info_db) {
9785 return nullptr;
9786 }
9787 if (!unavailable_channel_fulls_.insert(channel_id).second) {
9788 return nullptr;
9789 }
9790
9791 LOG(INFO) << "Trying to load full " << channel_id << " from database from " << source;
9792 on_load_channel_full_from_database(
9793 channel_id, G()->td_db()->get_sqlite_sync_pmc()->get(get_channel_full_database_key(channel_id)), source);
9794 return get_channel_full(channel_id, only_local, source);
9795 }
9796
for_each_secret_chat_with_user(UserId user_id,const std::function<void (SecretChatId)> & f)9797 void ContactsManager::for_each_secret_chat_with_user(UserId user_id, const std::function<void(SecretChatId)> &f) {
9798 auto it = secret_chats_with_user_.find(user_id);
9799 if (it != secret_chats_with_user_.end()) {
9800 for (auto secret_chat_id : it->second) {
9801 f(secret_chat_id);
9802 }
9803 }
9804 }
9805
update_user(User * u,UserId user_id,bool from_binlog,bool from_database)9806 void ContactsManager::update_user(User *u, UserId user_id, bool from_binlog, bool from_database) {
9807 CHECK(u != nullptr);
9808 if (u->is_name_changed || u->is_username_changed || u->is_is_contact_changed) {
9809 update_contacts_hints(u, user_id, from_database);
9810 u->is_username_changed = false;
9811 }
9812 if (u->is_is_contact_changed) {
9813 td_->messages_manager_->on_dialog_user_is_contact_updated(DialogId(user_id), u->is_contact);
9814 if (is_user_contact(u, user_id, false)) {
9815 auto user_full = get_user_full(user_id);
9816 if (user_full != nullptr && user_full->need_phone_number_privacy_exception) {
9817 on_update_user_full_need_phone_number_privacy_exception(user_full, user_id, false);
9818 update_user_full(user_full, user_id, "update_user");
9819 }
9820 }
9821 u->is_is_contact_changed = false;
9822 }
9823 if (u->is_is_deleted_changed) {
9824 td_->messages_manager_->on_dialog_user_is_deleted_updated(DialogId(user_id), u->is_deleted);
9825 if (u->is_deleted) {
9826 auto user_full = get_user_full(user_id); // must not load user_full from database before sending updateUser
9827 if (user_full != nullptr) {
9828 drop_user_full(user_id);
9829 }
9830 }
9831 u->is_is_deleted_changed = false;
9832 }
9833 if (u->is_name_changed) {
9834 auto messages_manager = td_->messages_manager_.get();
9835 messages_manager->on_dialog_title_updated(DialogId(user_id));
9836 for_each_secret_chat_with_user(user_id, [messages_manager](SecretChatId secret_chat_id) {
9837 messages_manager->on_dialog_title_updated(DialogId(secret_chat_id));
9838 });
9839 u->is_name_changed = false;
9840 }
9841 if (u->is_photo_changed) {
9842 auto messages_manager = td_->messages_manager_.get();
9843 messages_manager->on_dialog_photo_updated(DialogId(user_id));
9844 for_each_secret_chat_with_user(user_id, [messages_manager](SecretChatId secret_chat_id) {
9845 messages_manager->on_dialog_photo_updated(DialogId(secret_chat_id));
9846 });
9847 u->is_photo_changed = false;
9848 }
9849 if (u->is_status_changed && user_id != get_my_id()) {
9850 auto left_time = get_user_was_online(u, user_id) - G()->server_time_cached();
9851 if (left_time >= 0 && left_time < 30 * 86400) {
9852 left_time += 2.0; // to guarantee expiration
9853 LOG(DEBUG) << "Set online timeout for " << user_id << " in " << left_time;
9854 user_online_timeout_.set_timeout_in(user_id.get(), left_time);
9855 } else {
9856 LOG(DEBUG) << "Cancel online timeout for " << user_id;
9857 user_online_timeout_.cancel_timeout(user_id.get());
9858 }
9859 }
9860 if (!td_->auth_manager_->is_bot()) {
9861 if (u->restriction_reasons.empty()) {
9862 restricted_user_ids_.erase(user_id);
9863 } else {
9864 restricted_user_ids_.insert(user_id);
9865 }
9866 }
9867
9868 if (u->is_deleted) {
9869 td_->inline_queries_manager_->remove_recent_inline_bot(user_id, Promise<>());
9870 }
9871
9872 LOG(DEBUG) << "Update " << user_id << ": need_save_to_database = " << u->need_save_to_database
9873 << ", is_changed = " << u->is_changed << ", is_status_changed = " << u->is_status_changed;
9874 u->need_save_to_database |= u->is_changed;
9875 if (u->need_save_to_database) {
9876 if (!from_database) {
9877 u->is_saved = false;
9878 }
9879 u->need_save_to_database = false;
9880 }
9881 if (u->is_changed) {
9882 send_closure(G()->td(), &Td::send_update, make_tl_object<td_api::updateUser>(get_user_object(user_id, u)));
9883 u->is_changed = false;
9884 u->is_status_changed = false;
9885 u->is_update_user_sent = true;
9886 }
9887 if (u->is_status_changed) {
9888 if (!from_database) {
9889 u->is_status_saved = false;
9890 }
9891 CHECK(u->is_update_user_sent);
9892 send_closure(G()->td(), &Td::send_update,
9893 make_tl_object<td_api::updateUserStatus>(user_id.get(), get_user_status_object(user_id, u)));
9894 u->is_status_changed = false;
9895 }
9896 if (u->is_online_status_changed) {
9897 update_user_online_member_count(u);
9898 u->is_online_status_changed = false;
9899 }
9900
9901 if (!from_database) {
9902 save_user(u, user_id, from_binlog);
9903 }
9904
9905 if (u->cache_version != User::CACHE_VERSION && !u->is_repaired && have_input_peer_user(u, AccessRights::Read) &&
9906 !G()->close_flag()) {
9907 u->is_repaired = true;
9908
9909 LOG(INFO) << "Repairing cache of " << user_id;
9910 reload_user(user_id, Promise<Unit>());
9911 }
9912 }
9913
update_chat(Chat * c,ChatId chat_id,bool from_binlog,bool from_database)9914 void ContactsManager::update_chat(Chat *c, ChatId chat_id, bool from_binlog, bool from_database) {
9915 CHECK(c != nullptr);
9916 if (c->is_photo_changed) {
9917 td_->messages_manager_->on_dialog_photo_updated(DialogId(chat_id));
9918 drop_chat_photos(chat_id, !c->photo.small_file_id.is_valid(), true, "update_chat");
9919 c->is_photo_changed = false;
9920 }
9921 if (c->is_title_changed) {
9922 td_->messages_manager_->on_dialog_title_updated(DialogId(chat_id));
9923 c->is_title_changed = false;
9924 }
9925 if (c->is_default_permissions_changed) {
9926 td_->messages_manager_->on_dialog_default_permissions_updated(DialogId(chat_id));
9927 c->is_default_permissions_changed = false;
9928 }
9929 if (c->is_is_active_changed) {
9930 update_dialogs_for_discussion(DialogId(chat_id), c->is_active && c->status.is_creator());
9931 c->is_is_active_changed = false;
9932 }
9933 if (c->is_status_changed) {
9934 if (!c->status.can_manage_invite_links()) {
9935 td_->messages_manager_->drop_dialog_pending_join_requests(DialogId(chat_id));
9936 }
9937 c->is_status_changed = false;
9938 }
9939 if (c->is_noforwards_changed) {
9940 td_->messages_manager_->on_dialog_has_protected_content_updated(DialogId(chat_id));
9941 c->is_noforwards_changed = false;
9942 }
9943
9944 LOG(DEBUG) << "Update " << chat_id << ": need_save_to_database = " << c->need_save_to_database
9945 << ", is_changed = " << c->is_changed;
9946 c->need_save_to_database |= c->is_changed;
9947 if (c->need_save_to_database) {
9948 if (!from_database) {
9949 c->is_saved = false;
9950 }
9951 c->need_save_to_database = false;
9952 }
9953 if (c->is_changed) {
9954 send_closure(G()->td(), &Td::send_update,
9955 make_tl_object<td_api::updateBasicGroup>(get_basic_group_object(chat_id, c)));
9956 c->is_changed = false;
9957 c->is_update_basic_group_sent = true;
9958 }
9959
9960 if (!from_database) {
9961 save_chat(c, chat_id, from_binlog);
9962 }
9963
9964 if (c->cache_version != Chat::CACHE_VERSION && !c->is_repaired && have_input_peer_chat(c, AccessRights::Read) &&
9965 !G()->close_flag()) {
9966 c->is_repaired = true;
9967
9968 LOG(INFO) << "Repairing cache of " << chat_id;
9969 reload_chat(chat_id, Promise<Unit>());
9970 }
9971 }
9972
update_channel(Channel * c,ChannelId channel_id,bool from_binlog,bool from_database)9973 void ContactsManager::update_channel(Channel *c, ChannelId channel_id, bool from_binlog, bool from_database) {
9974 CHECK(c != nullptr);
9975 if (c->is_photo_changed) {
9976 td_->messages_manager_->on_dialog_photo_updated(DialogId(channel_id));
9977 drop_channel_photos(channel_id, !c->photo.small_file_id.is_valid(), true, "update_channel");
9978 c->is_photo_changed = false;
9979 }
9980 if (c->is_title_changed) {
9981 td_->messages_manager_->on_dialog_title_updated(DialogId(channel_id));
9982 c->is_title_changed = false;
9983 }
9984 if (c->is_status_changed) {
9985 c->status.update_restrictions();
9986 auto until_date = c->status.get_until_date();
9987 int32 left_time = 0;
9988 if (until_date > 0) {
9989 left_time = until_date - G()->unix_time_cached() + 1;
9990 CHECK(left_time > 0);
9991 }
9992 if (left_time > 0 && left_time < 366 * 86400) {
9993 channel_unban_timeout_.set_timeout_in(channel_id.get(), left_time);
9994 } else {
9995 channel_unban_timeout_.cancel_timeout(channel_id.get());
9996 }
9997
9998 if (c->is_megagroup) {
9999 update_dialogs_for_discussion(DialogId(channel_id), c->status.is_administrator() && c->status.can_pin_messages());
10000 }
10001 if (!c->status.is_member()) {
10002 remove_inactive_channel(channel_id);
10003 }
10004 if (!c->status.can_manage_invite_links()) {
10005 td_->messages_manager_->drop_dialog_pending_join_requests(DialogId(channel_id));
10006 }
10007 c->is_status_changed = false;
10008 }
10009 if (c->is_username_changed) {
10010 if (c->status.is_creator()) {
10011 update_created_public_channels(c, channel_id);
10012 }
10013 c->is_username_changed = false;
10014 }
10015 if (c->is_default_permissions_changed) {
10016 td_->messages_manager_->on_dialog_default_permissions_updated(DialogId(channel_id));
10017 if (c->default_permissions !=
10018 RestrictedRights(false, false, false, false, false, false, false, false, false, false, false)) {
10019 remove_dialog_suggested_action(SuggestedAction{SuggestedAction::Type::ConvertToGigagroup, DialogId(channel_id)});
10020 }
10021 c->is_default_permissions_changed = false;
10022 }
10023 if (c->is_has_location_changed) {
10024 if (c->status.is_creator()) {
10025 update_created_public_channels(c, channel_id);
10026 }
10027 c->is_has_location_changed = false;
10028 }
10029 if (c->is_creator_changed) {
10030 update_created_public_channels(c, channel_id);
10031 c->is_creator_changed = false;
10032 }
10033 if (c->is_noforwards_changed) {
10034 td_->messages_manager_->on_dialog_has_protected_content_updated(DialogId(channel_id));
10035 c->is_noforwards_changed = false;
10036 }
10037
10038 if (!td_->auth_manager_->is_bot()) {
10039 if (c->restriction_reasons.empty()) {
10040 restricted_channel_ids_.erase(channel_id);
10041 } else {
10042 restricted_channel_ids_.insert(channel_id);
10043 }
10044 }
10045
10046 LOG(DEBUG) << "Update " << channel_id << ": need_save_to_database = " << c->need_save_to_database
10047 << ", is_changed = " << c->is_changed;
10048 c->need_save_to_database |= c->is_changed;
10049 if (c->need_save_to_database) {
10050 if (!from_database) {
10051 c->is_saved = false;
10052 }
10053 c->need_save_to_database = false;
10054 }
10055 if (c->is_changed) {
10056 send_closure(G()->td(), &Td::send_update,
10057 make_tl_object<td_api::updateSupergroup>(get_supergroup_object(channel_id, c)));
10058 c->is_changed = false;
10059 c->is_update_supergroup_sent = true;
10060 }
10061
10062 if (!from_database) {
10063 save_channel(c, channel_id, from_binlog);
10064 }
10065
10066 bool have_read_access = have_input_peer_channel(c, channel_id, AccessRights::Read);
10067 bool is_member = c->status.is_member();
10068 if (c->had_read_access && !have_read_access) {
10069 send_closure_later(G()->messages_manager(), &MessagesManager::on_dialog_deleted, DialogId(channel_id),
10070 Promise<Unit>());
10071 } else if (!from_database && c->was_member != is_member) {
10072 DialogId dialog_id(channel_id);
10073 send_closure_later(G()->messages_manager(), &MessagesManager::force_create_dialog, dialog_id, "update channel",
10074 true, true);
10075 }
10076 c->had_read_access = have_read_access;
10077 c->was_member = is_member;
10078
10079 if (c->cache_version != Channel::CACHE_VERSION && !c->is_repaired &&
10080 have_input_peer_channel(c, channel_id, AccessRights::Read) && !G()->close_flag()) {
10081 c->is_repaired = true;
10082
10083 LOG(INFO) << "Repairing cache of " << channel_id;
10084 reload_channel(channel_id, Promise<Unit>());
10085 }
10086 }
10087
update_secret_chat(SecretChat * c,SecretChatId secret_chat_id,bool from_binlog,bool from_database)10088 void ContactsManager::update_secret_chat(SecretChat *c, SecretChatId secret_chat_id, bool from_binlog,
10089 bool from_database) {
10090 CHECK(c != nullptr);
10091 LOG(DEBUG) << "Update " << secret_chat_id << ": need_save_to_database = " << c->need_save_to_database
10092 << ", is_changed = " << c->is_changed;
10093 c->need_save_to_database |= c->is_changed;
10094 if (c->need_save_to_database) {
10095 if (!from_database) {
10096 c->is_saved = false;
10097 }
10098 c->need_save_to_database = false;
10099
10100 DialogId dialog_id(secret_chat_id);
10101 send_closure_later(G()->messages_manager(), &MessagesManager::force_create_dialog, dialog_id, "update secret chat",
10102 true, true);
10103 if (c->is_state_changed) {
10104 send_closure_later(G()->messages_manager(), &MessagesManager::on_update_secret_chat_state, secret_chat_id,
10105 c->state);
10106 c->is_state_changed = false;
10107 }
10108 if (c->is_ttl_changed) {
10109 send_closure_later(G()->messages_manager(), &MessagesManager::on_update_dialog_message_ttl_setting,
10110 DialogId(secret_chat_id), MessageTtlSetting(c->ttl));
10111 c->is_ttl_changed = false;
10112 }
10113 }
10114 if (c->is_changed) {
10115 send_closure(G()->td(), &Td::send_update,
10116 make_tl_object<td_api::updateSecretChat>(get_secret_chat_object(secret_chat_id, c)));
10117 c->is_changed = false;
10118 }
10119
10120 if (!from_database) {
10121 save_secret_chat(c, secret_chat_id, from_binlog);
10122 }
10123 }
10124
update_user_full(UserFull * user_full,UserId user_id,const char * source,bool from_database)10125 void ContactsManager::update_user_full(UserFull *user_full, UserId user_id, const char *source, bool from_database) {
10126 CHECK(user_full != nullptr);
10127 unavailable_user_fulls_.erase(user_id); // don't needed anymore
10128 if (user_full->is_common_chat_count_changed) {
10129 td_->messages_manager_->drop_common_dialogs_cache(user_id);
10130 user_full->is_common_chat_count_changed = false;
10131 }
10132
10133 user_full->need_send_update |= user_full->is_changed;
10134 user_full->need_save_to_database |= user_full->is_changed;
10135 user_full->is_changed = false;
10136 if (user_full->need_send_update || user_full->need_save_to_database) {
10137 LOG(INFO) << "Update full " << user_id << " from " << source;
10138 }
10139 if (user_full->need_send_update) {
10140 {
10141 auto u = get_user(user_id);
10142 CHECK(u == nullptr || u->is_update_user_sent);
10143 }
10144 if (!user_full->is_update_user_full_sent) {
10145 LOG(ERROR) << "Send partial updateUserFullInfo for " << user_id << " from " << source;
10146 user_full->is_update_user_full_sent = true;
10147 }
10148 send_closure(G()->td(), &Td::send_update,
10149 make_tl_object<td_api::updateUserFullInfo>(get_user_id_object(user_id, "updateUserFullInfo"),
10150 get_user_full_info_object(user_id, user_full)));
10151 user_full->need_send_update = false;
10152 }
10153 if (user_full->need_save_to_database) {
10154 if (!from_database) {
10155 save_user_full(user_full, user_id);
10156 }
10157 user_full->need_save_to_database = false;
10158 }
10159 }
10160
update_chat_full(ChatFull * chat_full,ChatId chat_id,const char * source,bool from_database)10161 void ContactsManager::update_chat_full(ChatFull *chat_full, ChatId chat_id, const char *source, bool from_database) {
10162 CHECK(chat_full != nullptr);
10163 unavailable_chat_fulls_.erase(chat_id); // don't needed anymore
10164
10165 chat_full->need_send_update |= chat_full->is_changed;
10166 chat_full->need_save_to_database |= chat_full->is_changed;
10167 chat_full->is_changed = false;
10168 if (chat_full->need_send_update || chat_full->need_save_to_database) {
10169 LOG(INFO) << "Update full " << chat_id << " from " << source;
10170 }
10171 if (chat_full->need_send_update) {
10172 vector<DialogAdministrator> administrators;
10173 vector<UserId> bot_user_ids;
10174 for (const auto &participant : chat_full->participants) {
10175 if (participant.status_.is_administrator() && participant.dialog_id_.get_type() == DialogType::User) {
10176 administrators.emplace_back(participant.dialog_id_.get_user_id(), participant.status_.get_rank(),
10177 participant.status_.is_creator());
10178 }
10179 if (participant.dialog_id_.get_type() == DialogType::User) {
10180 auto user_id = participant.dialog_id_.get_user_id();
10181 if (is_user_bot(user_id)) {
10182 bot_user_ids.push_back(user_id);
10183 }
10184 }
10185 }
10186 td::remove_if(chat_full->bot_commands, [&bot_user_ids](const BotCommands &commands) {
10187 return !td::contains(bot_user_ids, commands.get_bot_user_id());
10188 });
10189
10190 on_update_dialog_administrators(DialogId(chat_id), std::move(administrators), chat_full->version != -1,
10191 from_database);
10192 send_closure_later(G()->messages_manager(), &MessagesManager::on_dialog_bots_updated, DialogId(chat_id),
10193 std::move(bot_user_ids), from_database);
10194
10195 {
10196 Chat *c = get_chat(chat_id);
10197 CHECK(c == nullptr || c->is_update_basic_group_sent);
10198 }
10199 if (!chat_full->is_update_chat_full_sent) {
10200 LOG(ERROR) << "Send partial updateBasicGroupFullInfo for " << chat_id << " from " << source;
10201 chat_full->is_update_chat_full_sent = true;
10202 }
10203 send_closure(
10204 G()->td(), &Td::send_update,
10205 make_tl_object<td_api::updateBasicGroupFullInfo>(get_basic_group_id_object(chat_id, "update_chat_full"),
10206 get_basic_group_full_info_object(chat_full)));
10207 chat_full->need_send_update = false;
10208 }
10209 if (chat_full->need_save_to_database) {
10210 if (!from_database) {
10211 save_chat_full(chat_full, chat_id);
10212 }
10213 chat_full->need_save_to_database = false;
10214 }
10215 }
10216
update_channel_full(ChannelFull * channel_full,ChannelId channel_id,const char * source,bool from_database)10217 void ContactsManager::update_channel_full(ChannelFull *channel_full, ChannelId channel_id, const char *source,
10218 bool from_database) {
10219 CHECK(channel_full != nullptr);
10220 unavailable_channel_fulls_.erase(channel_id); // don't needed anymore
10221
10222 CHECK(channel_full->participant_count >= channel_full->administrator_count);
10223
10224 if (channel_full->is_slow_mode_next_send_date_changed) {
10225 auto now = G()->server_time();
10226 if (channel_full->slow_mode_next_send_date > now + 3601) {
10227 channel_full->slow_mode_next_send_date = static_cast<int32>(now) + 3601;
10228 }
10229 if (channel_full->slow_mode_next_send_date <= now) {
10230 channel_full->slow_mode_next_send_date = 0;
10231 }
10232 if (channel_full->slow_mode_next_send_date == 0) {
10233 slow_mode_delay_timeout_.cancel_timeout(channel_id.get());
10234 } else {
10235 slow_mode_delay_timeout_.set_timeout_in(channel_id.get(), channel_full->slow_mode_next_send_date - now + 0.002);
10236 }
10237 channel_full->is_slow_mode_next_send_date_changed = false;
10238 }
10239
10240 if (channel_full->need_save_to_database) {
10241 channel_full->is_changed |= td::remove_if(
10242 channel_full->bot_commands, [bot_user_ids = &channel_full->bot_user_ids](const BotCommands &commands) {
10243 return !td::contains(*bot_user_ids, commands.get_bot_user_id());
10244 });
10245 }
10246
10247 channel_full->need_send_update |= channel_full->is_changed;
10248 channel_full->need_save_to_database |= channel_full->is_changed;
10249 channel_full->is_changed = false;
10250 if (channel_full->need_send_update || channel_full->need_save_to_database) {
10251 LOG(INFO) << "Update full " << channel_id << " from " << source;
10252 }
10253 if (channel_full->need_send_update) {
10254 if (channel_full->linked_channel_id.is_valid()) {
10255 td_->messages_manager_->force_create_dialog(DialogId(channel_full->linked_channel_id), "update_channel_full",
10256 true);
10257 }
10258
10259 {
10260 Channel *c = get_channel(channel_id);
10261 CHECK(c == nullptr || c->is_update_supergroup_sent);
10262 }
10263 if (!channel_full->is_update_channel_full_sent) {
10264 LOG(ERROR) << "Send partial updateSupergroupFullInfo for " << channel_id << " from " << source;
10265 channel_full->is_update_channel_full_sent = true;
10266 }
10267 send_closure(
10268 G()->td(), &Td::send_update,
10269 make_tl_object<td_api::updateSupergroupFullInfo>(get_supergroup_id_object(channel_id, "update_channel_full"),
10270 get_supergroup_full_info_object(channel_full, channel_id)));
10271 channel_full->need_send_update = false;
10272 }
10273 if (channel_full->need_save_to_database) {
10274 if (!from_database) {
10275 save_channel_full(channel_full, channel_id);
10276 }
10277 channel_full->need_save_to_database = false;
10278 }
10279 }
10280
on_get_users(vector<tl_object_ptr<telegram_api::User>> && users,const char * source)10281 void ContactsManager::on_get_users(vector<tl_object_ptr<telegram_api::User>> &&users, const char *source) {
10282 for (auto &user : users) {
10283 on_get_user(std::move(user), source);
10284 }
10285 }
10286
on_get_user_full(tl_object_ptr<telegram_api::userFull> && user)10287 void ContactsManager::on_get_user_full(tl_object_ptr<telegram_api::userFull> &&user) {
10288 UserId user_id(user->id_);
10289 User *u = get_user(user_id);
10290 if (u == nullptr) {
10291 LOG(ERROR) << "Failed to find " << user_id;
10292 return;
10293 }
10294
10295 td_->messages_manager_->on_update_dialog_notify_settings(DialogId(user_id), std::move(user->notify_settings_),
10296 "on_get_user_full");
10297
10298 td_->messages_manager_->on_update_dialog_theme_name(DialogId(user_id), std::move(user->theme_emoticon_));
10299
10300 {
10301 MessageId pinned_message_id;
10302 if ((user->flags_ & USER_FULL_FLAG_HAS_PINNED_MESSAGE) != 0) {
10303 pinned_message_id = MessageId(ServerMessageId(user->pinned_msg_id_));
10304 }
10305 td_->messages_manager_->on_update_dialog_last_pinned_message_id(DialogId(user_id), pinned_message_id);
10306 }
10307 {
10308 FolderId folder_id;
10309 if ((user->flags_ & USER_FULL_FLAG_HAS_FOLDER_ID) != 0) {
10310 folder_id = FolderId(user->folder_id_);
10311 }
10312 td_->messages_manager_->on_update_dialog_folder_id(DialogId(user_id), folder_id);
10313 }
10314 td_->messages_manager_->on_update_dialog_has_scheduled_server_messages(
10315 DialogId(user_id), (user->flags_ & USER_FULL_FLAG_HAS_SCHEDULED_MESSAGES) != 0);
10316 {
10317 MessageTtlSetting message_ttl_setting;
10318 if ((user->flags_ & USER_FULL_FLAG_HAS_MESSAGE_TTL) != 0) {
10319 message_ttl_setting = MessageTtlSetting(user->ttl_period_);
10320 }
10321 td_->messages_manager_->on_update_dialog_message_ttl_setting(DialogId(user_id), message_ttl_setting);
10322 }
10323
10324 UserFull *user_full = add_user_full(user_id);
10325 user_full->expires_at = Time::now() + USER_FULL_EXPIRE_TIME;
10326
10327 {
10328 bool is_blocked = (user->flags_ & USER_FULL_FLAG_IS_BLOCKED) != 0;
10329 on_update_user_full_is_blocked(user_full, user_id, is_blocked);
10330 td_->messages_manager_->on_update_dialog_is_blocked(DialogId(user_id), is_blocked);
10331 }
10332
10333 on_update_user_full_common_chat_count(user_full, user_id, user->common_chats_count_);
10334 on_update_user_full_need_phone_number_privacy_exception(user_full, user_id,
10335 user->settings_->need_contacts_exception_);
10336
10337 bool can_pin_messages = user->can_pin_message_;
10338 if (user_full->can_pin_messages != can_pin_messages) {
10339 user_full->can_pin_messages = can_pin_messages;
10340 user_full->is_changed = true;
10341 }
10342
10343 bool can_be_called = user->phone_calls_available_ && !user->phone_calls_private_;
10344 bool supports_video_calls = user->video_calls_available_ && !user->phone_calls_private_;
10345 bool has_private_calls = user->phone_calls_private_;
10346 if (user_full->can_be_called != can_be_called || user_full->supports_video_calls != supports_video_calls ||
10347 user_full->has_private_calls != has_private_calls ||
10348 user_full->private_forward_name != user->private_forward_name_) {
10349 user_full->can_be_called = can_be_called;
10350 user_full->supports_video_calls = supports_video_calls;
10351 user_full->has_private_calls = has_private_calls;
10352 user_full->private_forward_name = std::move(user->private_forward_name_);
10353
10354 user_full->is_changed = true;
10355 }
10356 if (user_full->about != user->about_) {
10357 user_full->about = std::move(user->about_);
10358 user_full->is_changed = true;
10359 td_->group_call_manager_->on_update_dialog_about(DialogId(user_id), user_full->about, true);
10360 }
10361 string description;
10362 if (user->bot_info_ != nullptr && !td_->auth_manager_->is_bot()) {
10363 description = std::move(user->bot_info_->description_);
10364
10365 on_update_user_full_commands(user_full, user_id, std::move(user->bot_info_->commands_));
10366 }
10367 if (user_full->description != description) {
10368 user_full->description = std::move(description);
10369 user_full->is_changed = true;
10370 }
10371
10372 auto photo = get_photo(td_->file_manager_.get(), std::move(user->profile_photo_), DialogId(user_id));
10373 if (photo != user_full->photo) {
10374 user_full->photo = std::move(photo);
10375 user_full->is_changed = true;
10376 }
10377 if (user_full->photo.is_empty()) {
10378 drop_user_photos(user_id, true, false, "on_get_user_full");
10379 } else {
10380 register_user_photo(u, user_id, user_full->photo);
10381 }
10382
10383 user_full->is_update_user_full_sent = true;
10384 update_user_full(user_full, user_id, "on_get_user_full");
10385
10386 // update peer settings after UserFull is created and updated to not update twice need_phone_number_privacy_exception
10387 td_->messages_manager_->on_get_peer_settings(DialogId(user_id), std::move(user->settings_));
10388 }
10389
on_get_user_photos(UserId user_id,int32 offset,int32 limit,int32 total_count,vector<tl_object_ptr<telegram_api::Photo>> photos)10390 void ContactsManager::on_get_user_photos(UserId user_id, int32 offset, int32 limit, int32 total_count,
10391 vector<tl_object_ptr<telegram_api::Photo>> photos) {
10392 auto photo_count = narrow_cast<int32>(photos.size());
10393 int32 min_total_count = (offset >= 0 && photo_count > 0 ? offset : 0) + photo_count;
10394 if (total_count < min_total_count) {
10395 LOG(ERROR) << "Wrong photos total_count " << total_count << ". Receive " << photo_count << " photos with offset "
10396 << offset;
10397 total_count = min_total_count;
10398 }
10399 LOG_IF(ERROR, limit < photo_count) << "Requested not more than " << limit << " photos, but " << photo_count
10400 << " received";
10401
10402 User *u = get_user(user_id);
10403 if (u == nullptr) {
10404 LOG(ERROR) << "Can't find " << user_id;
10405 return;
10406 }
10407
10408 if (offset == -1) {
10409 // from reload_user_profile_photo
10410 CHECK(limit == 1);
10411 for (auto &photo_ptr : photos) {
10412 if (photo_ptr->get_id() == telegram_api::photo::ID) {
10413 auto server_photo = telegram_api::move_object_as<telegram_api::photo>(photo_ptr);
10414 if (server_photo->id_ == u->photo.id) {
10415 auto profile_photo = convert_photo_to_profile_photo(server_photo);
10416 if (profile_photo) {
10417 LOG_IF(ERROR, u->access_hash == -1) << "Receive profile photo of " << user_id << " without access hash";
10418 get_profile_photo(td_->file_manager_.get(), user_id, u->access_hash, std::move(profile_photo));
10419 } else {
10420 LOG(ERROR) << "Failed to get profile photo from " << to_string(server_photo);
10421 }
10422 }
10423
10424 auto photo = get_photo(td_->file_manager_.get(), std::move(server_photo), DialogId(user_id));
10425 register_user_photo(u, user_id, photo);
10426 }
10427 }
10428 return;
10429 }
10430
10431 LOG(INFO) << "Receive " << photo_count << " photos of " << user_id << " out of " << total_count << " with offset "
10432 << offset << " and limit " << limit;
10433 UserPhotos *user_photos = &user_photos_[user_id];
10434 user_photos->count = total_count;
10435 CHECK(user_photos->getting_now);
10436 user_photos->getting_now = false;
10437
10438 if (user_photos->offset == -1) {
10439 user_photos->offset = 0;
10440 CHECK(user_photos->photos.empty());
10441 }
10442
10443 if (offset != narrow_cast<int32>(user_photos->photos.size()) + user_photos->offset) {
10444 LOG(INFO) << "Inappropriate offset to append " << user_id << " profile photos to cache: offset = " << offset
10445 << ", current_offset = " << user_photos->offset << ", photo_count = " << user_photos->photos.size();
10446 user_photos->photos.clear();
10447 user_photos->offset = offset;
10448 }
10449
10450 for (auto &photo : photos) {
10451 auto user_photo = get_photo(td_->file_manager_.get(), std::move(photo), DialogId(user_id));
10452 if (user_photo.is_empty()) {
10453 LOG(ERROR) << "Receive empty profile photo in getUserPhotos request for " << user_id << " with offset " << offset
10454 << " and limit " << limit << ". Receive " << photo_count << " photos out of " << total_count
10455 << " photos";
10456 user_photos->count--;
10457 CHECK(user_photos->count >= 0);
10458 continue;
10459 }
10460
10461 user_photos->photos.push_back(std::move(user_photo));
10462 register_user_photo(u, user_id, user_photos->photos.back());
10463 }
10464 if (user_photos->offset > user_photos->count) {
10465 user_photos->offset = user_photos->count;
10466 user_photos->photos.clear();
10467 }
10468
10469 auto known_photo_count = narrow_cast<int32>(user_photos->photos.size());
10470 if (user_photos->offset + known_photo_count > user_photos->count) {
10471 user_photos->photos.resize(user_photos->count - user_photos->offset);
10472 }
10473 }
10474
on_get_chat(tl_object_ptr<telegram_api::Chat> && chat,const char * source)10475 void ContactsManager::on_get_chat(tl_object_ptr<telegram_api::Chat> &&chat, const char *source) {
10476 LOG(DEBUG) << "Receive from " << source << ' ' << to_string(chat);
10477 downcast_call(*chat, [this, source](auto &c) { this->on_chat_update(c, source); });
10478 }
10479
on_get_chats(vector<tl_object_ptr<telegram_api::Chat>> && chats,const char * source)10480 void ContactsManager::on_get_chats(vector<tl_object_ptr<telegram_api::Chat>> &&chats, const char *source) {
10481 for (auto &chat : chats) {
10482 auto constuctor_id = chat->get_id();
10483 if (constuctor_id == telegram_api::channel::ID || constuctor_id == telegram_api::channelForbidden::ID) {
10484 // apply info about megagroups before corresponding chats
10485 on_get_chat(std::move(chat), source);
10486 chat = nullptr;
10487 }
10488 }
10489 for (auto &chat : chats) {
10490 if (chat != nullptr) {
10491 on_get_chat(std::move(chat), source);
10492 chat = nullptr;
10493 }
10494 }
10495 }
10496
get_bot_commands(vector<tl_object_ptr<telegram_api::botInfo>> && bot_infos,const vector<DialogParticipant> * participants)10497 vector<BotCommands> ContactsManager::get_bot_commands(vector<tl_object_ptr<telegram_api::botInfo>> &&bot_infos,
10498 const vector<DialogParticipant> *participants) {
10499 vector<BotCommands> result;
10500 if (td_->auth_manager_->is_bot()) {
10501 return result;
10502 }
10503 for (auto &bot_info : bot_infos) {
10504 if (bot_info->commands_.empty()) {
10505 continue;
10506 }
10507
10508 auto user_id = UserId(bot_info->user_id_);
10509 if (!have_user_force(user_id)) {
10510 LOG(ERROR) << "Receive unknown " << user_id;
10511 continue;
10512 }
10513 if (!is_user_bot(user_id)) {
10514 if (!is_user_deleted(user_id)) {
10515 LOG(ERROR) << "Receive non-bot " << user_id;
10516 }
10517 continue;
10518 }
10519 if (participants != nullptr) {
10520 bool is_participant = false;
10521 for (auto &participant : *participants) {
10522 if (participant.dialog_id_ == DialogId(user_id)) {
10523 is_participant = true;
10524 break;
10525 }
10526 }
10527 if (!is_participant) {
10528 LOG(ERROR) << "Skip commands of non-member bot " << user_id;
10529 continue;
10530 }
10531 }
10532 result.emplace_back(user_id, std::move(bot_info->commands_));
10533 }
10534 return result;
10535 }
10536
on_get_chat_full(tl_object_ptr<telegram_api::ChatFull> && chat_full_ptr,Promise<Unit> && promise)10537 void ContactsManager::on_get_chat_full(tl_object_ptr<telegram_api::ChatFull> &&chat_full_ptr, Promise<Unit> &&promise) {
10538 LOG(INFO) << "Receive " << to_string(chat_full_ptr);
10539 if (chat_full_ptr->get_id() == telegram_api::chatFull::ID) {
10540 auto chat = move_tl_object_as<telegram_api::chatFull>(chat_full_ptr);
10541 ChatId chat_id(chat->id_);
10542 if (!chat_id.is_valid()) {
10543 LOG(ERROR) << "Receive invalid " << chat_id;
10544 return promise.set_value(Unit());
10545 }
10546
10547 {
10548 MessageId pinned_message_id;
10549 if ((chat->flags_ & CHAT_FULL_FLAG_HAS_PINNED_MESSAGE) != 0) {
10550 pinned_message_id = MessageId(ServerMessageId(chat->pinned_msg_id_));
10551 }
10552 Chat *c = get_chat(chat_id);
10553 if (c == nullptr) {
10554 LOG(ERROR) << "Can't find " << chat_id;
10555 return promise.set_value(Unit());
10556 } else if (c->version >= c->pinned_message_version) {
10557 LOG(INFO) << "Receive pinned " << pinned_message_id << " in " << chat_id << " with version " << c->version
10558 << ". Current version is " << c->pinned_message_version;
10559 td_->messages_manager_->on_update_dialog_last_pinned_message_id(DialogId(chat_id), pinned_message_id);
10560 if (c->version > c->pinned_message_version) {
10561 c->pinned_message_version = c->version;
10562 c->need_save_to_database = true;
10563 update_chat(c, chat_id);
10564 }
10565 }
10566 }
10567 {
10568 FolderId folder_id;
10569 if ((chat->flags_ & CHAT_FULL_FLAG_HAS_FOLDER_ID) != 0) {
10570 folder_id = FolderId(chat->folder_id_);
10571 }
10572 td_->messages_manager_->on_update_dialog_folder_id(DialogId(chat_id), folder_id);
10573 }
10574 td_->messages_manager_->on_update_dialog_has_scheduled_server_messages(
10575 DialogId(chat_id), (chat->flags_ & CHAT_FULL_FLAG_HAS_SCHEDULED_MESSAGES) != 0);
10576 {
10577 InputGroupCallId input_group_call_id;
10578 if (chat->call_ != nullptr) {
10579 input_group_call_id = InputGroupCallId(chat->call_);
10580 }
10581 td_->messages_manager_->on_update_dialog_group_call_id(DialogId(chat_id), input_group_call_id);
10582 }
10583 {
10584 DialogId default_join_group_call_as_dialog_id;
10585 if (chat->groupcall_default_join_as_ != nullptr) {
10586 default_join_group_call_as_dialog_id = DialogId(chat->groupcall_default_join_as_);
10587 }
10588 // use send closure later to not create synchronously default_join_group_call_as_dialog_id
10589 send_closure_later(G()->messages_manager(),
10590 &MessagesManager::on_update_dialog_default_join_group_call_as_dialog_id, DialogId(chat_id),
10591 default_join_group_call_as_dialog_id, false);
10592 }
10593 {
10594 MessageTtlSetting message_ttl_setting;
10595 if ((chat->flags_ & CHAT_FULL_FLAG_HAS_MESSAGE_TTL) != 0) {
10596 message_ttl_setting = MessageTtlSetting(chat->ttl_period_);
10597 }
10598 td_->messages_manager_->on_update_dialog_message_ttl_setting(DialogId(chat_id), message_ttl_setting);
10599 }
10600
10601 ChatFull *chat_full = add_chat_full(chat_id);
10602 on_update_chat_full_invite_link(chat_full, std::move(chat->exported_invite_));
10603 on_update_chat_full_photo(chat_full, chat_id,
10604 get_photo(td_->file_manager_.get(), std::move(chat->chat_photo_), DialogId(chat_id)));
10605 if (chat_full->description != chat->about_) {
10606 chat_full->description = std::move(chat->about_);
10607 chat_full->is_changed = true;
10608 td_->group_call_manager_->on_update_dialog_about(DialogId(chat_id), chat_full->description, true);
10609 }
10610 if (chat_full->can_set_username != chat->can_set_username_) {
10611 chat_full->can_set_username = chat->can_set_username_;
10612 chat_full->is_changed = true;
10613 }
10614
10615 on_get_chat_participants(std::move(chat->participants_), false);
10616 td_->messages_manager_->on_update_dialog_notify_settings(DialogId(chat_id), std::move(chat->notify_settings_),
10617 "on_get_chat_full");
10618
10619 td_->messages_manager_->on_update_dialog_theme_name(DialogId(chat_id), std::move(chat->theme_emoticon_));
10620
10621 td_->messages_manager_->on_update_dialog_pending_join_requests(DialogId(chat_id), chat->requests_pending_,
10622 std::move(chat->recent_requesters_));
10623
10624 auto bot_commands = get_bot_commands(std::move(chat->bot_info_), &chat_full->participants);
10625 if (chat_full->bot_commands != bot_commands) {
10626 chat_full->bot_commands = std::move(bot_commands);
10627 chat_full->is_changed = true;
10628 }
10629
10630 chat_full->is_update_chat_full_sent = true;
10631 update_chat_full(chat_full, chat_id, "on_get_chat_full");
10632 } else {
10633 CHECK(chat_full_ptr->get_id() == telegram_api::channelFull::ID);
10634 auto channel = move_tl_object_as<telegram_api::channelFull>(chat_full_ptr);
10635 ChannelId channel_id(channel->id_);
10636 if (!channel_id.is_valid()) {
10637 LOG(ERROR) << "Receive invalid " << channel_id;
10638 return promise.set_value(Unit());
10639 }
10640
10641 invalidated_channels_full_.erase(channel_id);
10642
10643 if (!G()->close_flag()) {
10644 auto channel_full = get_channel_full(channel_id, true, "on_get_channel_full");
10645 if (channel_full != nullptr) {
10646 if (channel_full->repair_request_version != 0 &&
10647 channel_full->repair_request_version < channel_full->speculative_version) {
10648 LOG(INFO) << "Receive ChannelFull with request version " << channel_full->repair_request_version
10649 << ", but current speculative version is " << channel_full->speculative_version;
10650
10651 channel_full->repair_request_version = channel_full->speculative_version;
10652
10653 auto input_channel = get_input_channel(channel_id);
10654 CHECK(input_channel != nullptr);
10655 td_->create_handler<GetFullChannelQuery>(std::move(promise))->send(channel_id, std::move(input_channel));
10656 return;
10657 }
10658 channel_full->repair_request_version = 0;
10659 }
10660 }
10661
10662 td_->messages_manager_->on_update_dialog_notify_settings(DialogId(channel_id), std::move(channel->notify_settings_),
10663 "on_get_channel_full");
10664
10665 td_->messages_manager_->on_update_dialog_theme_name(DialogId(channel_id), std::move(channel->theme_emoticon_));
10666
10667 td_->messages_manager_->on_update_dialog_pending_join_requests(DialogId(channel_id), channel->requests_pending_,
10668 std::move(channel->recent_requesters_));
10669
10670 {
10671 MessageTtlSetting message_ttl_setting;
10672 if ((channel->flags_ & CHANNEL_FULL_FLAG_HAS_MESSAGE_TTL) != 0) {
10673 message_ttl_setting = MessageTtlSetting(channel->ttl_period_);
10674 }
10675 td_->messages_manager_->on_update_dialog_message_ttl_setting(DialogId(channel_id), message_ttl_setting);
10676 }
10677
10678 auto c = get_channel(channel_id);
10679 if (c == nullptr) {
10680 LOG(ERROR) << channel_id << " not found";
10681 return promise.set_value(Unit());
10682 }
10683
10684 ChannelFull *channel_full = add_channel_full(channel_id);
10685
10686 bool have_participant_count = (channel->flags_ & CHANNEL_FULL_FLAG_HAS_PARTICIPANT_COUNT) != 0;
10687 auto participant_count = have_participant_count ? channel->participants_count_ : channel_full->participant_count;
10688 auto administrator_count = 0;
10689 if ((channel->flags_ & CHANNEL_FULL_FLAG_HAS_ADMINISTRATOR_COUNT) != 0) {
10690 administrator_count = channel->admins_count_;
10691 } else if (c->is_megagroup || c->status.is_administrator()) {
10692 // in megagroups and administered channels don't drop known number of administrators
10693 administrator_count = channel_full->administrator_count;
10694 }
10695 if (participant_count < administrator_count) {
10696 participant_count = administrator_count;
10697 }
10698 auto restricted_count = (channel->flags_ & CHANNEL_FULL_FLAG_HAS_BANNED_COUNT) != 0 ? channel->banned_count_ : 0;
10699 auto banned_count = (channel->flags_ & CHANNEL_FULL_FLAG_HAS_BANNED_COUNT) != 0 ? channel->kicked_count_ : 0;
10700 auto can_get_participants = (channel->flags_ & CHANNEL_FULL_FLAG_CAN_GET_PARTICIPANTS) != 0;
10701 auto can_set_username = (channel->flags_ & CHANNEL_FULL_FLAG_CAN_SET_USERNAME) != 0;
10702 auto can_set_sticker_set = (channel->flags_ & CHANNEL_FULL_FLAG_CAN_SET_STICKER_SET) != 0;
10703 auto can_set_location = (channel->flags_ & CHANNEL_FULL_FLAG_CAN_SET_LOCATION) != 0;
10704 auto is_all_history_available = (channel->flags_ & CHANNEL_FULL_FLAG_IS_ALL_HISTORY_HIDDEN) == 0;
10705 auto can_view_statistics = (channel->flags_ & CHANNEL_FULL_FLAG_CAN_VIEW_STATISTICS) != 0;
10706 StickerSetId sticker_set_id;
10707 if (channel->stickerset_ != nullptr) {
10708 sticker_set_id =
10709 td_->stickers_manager_->on_get_sticker_set(std::move(channel->stickerset_), true, "on_get_channel_full");
10710 }
10711 DcId stats_dc_id;
10712 if ((channel->flags_ & CHANNEL_FULL_FLAG_HAS_STATISTICS_DC_ID) != 0) {
10713 stats_dc_id = DcId::create(channel->stats_dc_);
10714 }
10715 if (!stats_dc_id.is_exact() && can_view_statistics) {
10716 LOG(ERROR) << "Receive can_view_statistics == true, but invalid statistics DC ID in " << channel_id;
10717 can_view_statistics = false;
10718 }
10719
10720 channel_full->repair_request_version = 0;
10721 channel_full->expires_at = Time::now() + CHANNEL_FULL_EXPIRE_TIME;
10722 if (channel_full->participant_count != participant_count ||
10723 channel_full->administrator_count != administrator_count ||
10724 channel_full->restricted_count != restricted_count || channel_full->banned_count != banned_count ||
10725 channel_full->can_get_participants != can_get_participants ||
10726 channel_full->can_set_username != can_set_username ||
10727 channel_full->can_set_sticker_set != can_set_sticker_set ||
10728 channel_full->can_set_location != can_set_location ||
10729 channel_full->can_view_statistics != can_view_statistics || channel_full->stats_dc_id != stats_dc_id ||
10730 channel_full->sticker_set_id != sticker_set_id ||
10731 channel_full->is_all_history_available != is_all_history_available) {
10732 channel_full->participant_count = participant_count;
10733 channel_full->administrator_count = administrator_count;
10734 channel_full->restricted_count = restricted_count;
10735 channel_full->banned_count = banned_count;
10736 channel_full->can_get_participants = can_get_participants;
10737 channel_full->can_set_username = can_set_username;
10738 channel_full->can_set_sticker_set = can_set_sticker_set;
10739 channel_full->can_set_location = can_set_location;
10740 channel_full->can_view_statistics = can_view_statistics;
10741 channel_full->stats_dc_id = stats_dc_id;
10742 channel_full->is_all_history_available = is_all_history_available;
10743 channel_full->sticker_set_id = sticker_set_id;
10744
10745 channel_full->is_changed = true;
10746 }
10747 if (channel_full->description != channel->about_) {
10748 channel_full->description = std::move(channel->about_);
10749 channel_full->is_changed = true;
10750 td_->group_call_manager_->on_update_dialog_about(DialogId(channel_id), channel_full->description, true);
10751 }
10752
10753 if (have_participant_count && c->participant_count != participant_count) {
10754 c->participant_count = participant_count;
10755 c->is_changed = true;
10756 update_channel(c, channel_id);
10757 }
10758 if (!channel_full->is_can_view_statistics_inited) {
10759 channel_full->is_can_view_statistics_inited = true;
10760 channel_full->need_save_to_database = true;
10761 }
10762
10763 on_update_channel_full_photo(
10764 channel_full, channel_id,
10765 get_photo(td_->file_manager_.get(), std::move(channel->chat_photo_), DialogId(channel_id)));
10766
10767 td_->messages_manager_->on_read_channel_outbox(channel_id,
10768 MessageId(ServerMessageId(channel->read_outbox_max_id_)));
10769 if ((channel->flags_ & CHANNEL_FULL_FLAG_HAS_AVAILABLE_MIN_MESSAGE_ID) != 0) {
10770 td_->messages_manager_->on_update_channel_max_unavailable_message_id(
10771 channel_id, MessageId(ServerMessageId(channel->available_min_id_)));
10772 }
10773 td_->messages_manager_->on_read_channel_inbox(channel_id, MessageId(ServerMessageId(channel->read_inbox_max_id_)),
10774 channel->unread_count_, channel->pts_, "ChannelFull");
10775
10776 on_update_channel_full_invite_link(channel_full, std::move(channel->exported_invite_));
10777
10778 {
10779 auto is_blocked = (channel->flags_ & CHANNEL_FULL_FLAG_IS_BLOCKED) != 0;
10780 td_->messages_manager_->on_update_dialog_is_blocked(DialogId(channel_id), is_blocked);
10781 }
10782 {
10783 MessageId pinned_message_id;
10784 if ((channel->flags_ & CHANNEL_FULL_FLAG_HAS_PINNED_MESSAGE) != 0) {
10785 pinned_message_id = MessageId(ServerMessageId(channel->pinned_msg_id_));
10786 }
10787 td_->messages_manager_->on_update_dialog_last_pinned_message_id(DialogId(channel_id), pinned_message_id);
10788 }
10789 {
10790 FolderId folder_id;
10791 if ((channel->flags_ & CHANNEL_FULL_FLAG_HAS_FOLDER_ID) != 0) {
10792 folder_id = FolderId(channel->folder_id_);
10793 }
10794 td_->messages_manager_->on_update_dialog_folder_id(DialogId(channel_id), folder_id);
10795 }
10796 td_->messages_manager_->on_update_dialog_has_scheduled_server_messages(
10797 DialogId(channel_id), (channel->flags_ & CHANNEL_FULL_FLAG_HAS_SCHEDULED_MESSAGES) != 0);
10798 {
10799 InputGroupCallId input_group_call_id;
10800 if (channel->call_ != nullptr) {
10801 input_group_call_id = InputGroupCallId(channel->call_);
10802 }
10803 td_->messages_manager_->on_update_dialog_group_call_id(DialogId(channel_id), input_group_call_id);
10804 }
10805 {
10806 DialogId default_join_group_call_as_dialog_id;
10807 if (channel->groupcall_default_join_as_ != nullptr) {
10808 default_join_group_call_as_dialog_id = DialogId(channel->groupcall_default_join_as_);
10809 }
10810 // use send closure later to not create synchronously default_join_group_call_as_dialog_id
10811 send_closure_later(G()->messages_manager(),
10812 &MessagesManager::on_update_dialog_default_join_group_call_as_dialog_id, DialogId(channel_id),
10813 default_join_group_call_as_dialog_id, false);
10814 }
10815 {
10816 DialogId default_send_message_as_dialog_id;
10817 if (channel->default_send_as_ != nullptr) {
10818 default_send_message_as_dialog_id = DialogId(channel->default_send_as_);
10819 }
10820 // use send closure later to not create synchronously default_send_message_as_dialog_id
10821 send_closure_later(G()->messages_manager(), &MessagesManager::on_update_dialog_default_send_message_as_dialog_id,
10822 DialogId(channel_id), default_send_message_as_dialog_id, false);
10823 }
10824
10825 if (participant_count >= 190) {
10826 int32 online_member_count = 0;
10827 if ((channel->flags_ & CHANNEL_FULL_FLAG_HAS_ONLINE_MEMBER_COUNT) != 0) {
10828 online_member_count = channel->online_count_;
10829 }
10830 td_->messages_manager_->on_update_dialog_online_member_count(DialogId(channel_id), online_member_count, true);
10831 }
10832
10833 vector<UserId> bot_user_ids;
10834 for (const auto &bot_info : channel->bot_info_) {
10835 UserId user_id(bot_info->user_id_);
10836 if (!is_user_bot(user_id)) {
10837 continue;
10838 }
10839
10840 bot_user_ids.push_back(user_id);
10841 }
10842 on_update_channel_full_bot_user_ids(channel_full, channel_id, std::move(bot_user_ids));
10843
10844 auto bot_commands = get_bot_commands(std::move(channel->bot_info_), nullptr);
10845 if (channel_full->bot_commands != bot_commands) {
10846 channel_full->bot_commands = std::move(bot_commands);
10847 channel_full->is_changed = true;
10848 }
10849
10850 ChannelId linked_channel_id;
10851 if ((channel->flags_ & CHANNEL_FULL_FLAG_HAS_LINKED_CHANNEL_ID) != 0) {
10852 linked_channel_id = ChannelId(channel->linked_chat_id_);
10853 auto linked_channel = get_channel_force(linked_channel_id);
10854 if (linked_channel == nullptr || c->is_megagroup == linked_channel->is_megagroup ||
10855 channel_id == linked_channel_id) {
10856 LOG(ERROR) << "Failed to add a link between " << channel_id << " and " << linked_channel_id;
10857 linked_channel_id = ChannelId();
10858 }
10859 }
10860 on_update_channel_full_linked_channel_id(channel_full, channel_id, linked_channel_id);
10861
10862 on_update_channel_full_location(channel_full, channel_id, DialogLocation(std::move(channel->location_)));
10863
10864 if (c->is_megagroup) {
10865 int32 slow_mode_delay = 0;
10866 int32 slow_mode_next_send_date = 0;
10867 if ((channel->flags_ & CHANNEL_FULL_FLAG_HAS_SLOW_MODE_DELAY) != 0) {
10868 slow_mode_delay = channel->slowmode_seconds_;
10869 }
10870 if ((channel->flags_ & CHANNEL_FULL_FLAG_HAS_SLOW_MODE_NEXT_SEND_DATE) != 0) {
10871 slow_mode_next_send_date = channel->slowmode_next_send_date_;
10872 }
10873 on_update_channel_full_slow_mode_delay(channel_full, channel_id, slow_mode_delay, slow_mode_next_send_date);
10874 }
10875
10876 ChatId migrated_from_chat_id;
10877 MessageId migrated_from_max_message_id;
10878
10879 if ((channel->flags_ & CHANNEL_FULL_FLAG_MIGRATED_FROM) != 0) {
10880 migrated_from_chat_id = ChatId(channel->migrated_from_chat_id_);
10881 migrated_from_max_message_id = MessageId(ServerMessageId(channel->migrated_from_max_id_));
10882 }
10883
10884 if (channel_full->migrated_from_chat_id != migrated_from_chat_id ||
10885 channel_full->migrated_from_max_message_id != migrated_from_max_message_id) {
10886 channel_full->migrated_from_chat_id = migrated_from_chat_id;
10887 channel_full->migrated_from_max_message_id = migrated_from_max_message_id;
10888 channel_full->is_changed = true;
10889 }
10890
10891 channel_full->is_update_channel_full_sent = true;
10892 update_channel_full(channel_full, channel_id, "on_get_channel_full");
10893
10894 if (linked_channel_id.is_valid()) {
10895 auto linked_channel_full = get_channel_full_force(linked_channel_id, true, "on_get_chat_full");
10896 on_update_channel_full_linked_channel_id(linked_channel_full, linked_channel_id, channel_id);
10897 if (linked_channel_full != nullptr) {
10898 update_channel_full(linked_channel_full, linked_channel_id, "on_get_channel_full 2");
10899 }
10900 }
10901
10902 if (dismiss_suggested_action_queries_.count(DialogId(channel_id)) == 0) {
10903 auto it = dialog_suggested_actions_.find(DialogId(channel_id));
10904 if (it != dialog_suggested_actions_.end() || !channel->pending_suggestions_.empty()) {
10905 vector<SuggestedAction> suggested_actions;
10906 for (auto &action_str : channel->pending_suggestions_) {
10907 SuggestedAction suggested_action(action_str, DialogId(channel_id));
10908 if (!suggested_action.is_empty()) {
10909 if (suggested_action == SuggestedAction{SuggestedAction::Type::ConvertToGigagroup, DialogId(channel_id)} &&
10910 (c->is_gigagroup || c->default_permissions != RestrictedRights(false, false, false, false, false, false,
10911 false, false, false, false, false))) {
10912 LOG(INFO) << "Skip ConvertToGigagroup suggested action";
10913 } else {
10914 suggested_actions.push_back(suggested_action);
10915 }
10916 }
10917 }
10918 if (it == dialog_suggested_actions_.end()) {
10919 it = dialog_suggested_actions_.emplace(DialogId(channel_id), vector<SuggestedAction>()).first;
10920 }
10921 update_suggested_actions(it->second, std::move(suggested_actions));
10922 if (it->second.empty()) {
10923 dialog_suggested_actions_.erase(it);
10924 }
10925 }
10926 }
10927 }
10928 promise.set_value(Unit());
10929 }
10930
on_get_chat_full_failed(ChatId chat_id)10931 void ContactsManager::on_get_chat_full_failed(ChatId chat_id) {
10932 if (G()->close_flag()) {
10933 return;
10934 }
10935
10936 LOG(INFO) << "Failed to get full " << chat_id;
10937 }
10938
on_get_channel_full_failed(ChannelId channel_id)10939 void ContactsManager::on_get_channel_full_failed(ChannelId channel_id) {
10940 if (G()->close_flag()) {
10941 return;
10942 }
10943
10944 LOG(INFO) << "Failed to get full " << channel_id;
10945 auto channel_full = get_channel_full(channel_id, true, "on_get_channel_full");
10946 if (channel_full != nullptr) {
10947 channel_full->repair_request_version = 0;
10948 }
10949 }
10950
is_update_about_username_change_received(UserId user_id) const10951 bool ContactsManager::is_update_about_username_change_received(UserId user_id) const {
10952 const User *u = get_user(user_id);
10953 if (u != nullptr) {
10954 return u->is_contact;
10955 } else {
10956 return false;
10957 }
10958 }
10959
on_update_user_name(UserId user_id,string && first_name,string && last_name,string && username)10960 void ContactsManager::on_update_user_name(UserId user_id, string &&first_name, string &&last_name, string &&username) {
10961 if (!user_id.is_valid()) {
10962 LOG(ERROR) << "Receive invalid " << user_id;
10963 return;
10964 }
10965
10966 User *u = get_user_force(user_id);
10967 if (u != nullptr) {
10968 on_update_user_name(u, user_id, std::move(first_name), std::move(last_name), std::move(username));
10969 update_user(u, user_id);
10970 } else {
10971 LOG(INFO) << "Ignore update user name about unknown " << user_id;
10972 }
10973 }
10974
on_update_user_name(User * u,UserId user_id,string && first_name,string && last_name,string && username)10975 void ContactsManager::on_update_user_name(User *u, UserId user_id, string &&first_name, string &&last_name,
10976 string &&username) {
10977 if (first_name.empty() && last_name.empty()) {
10978 first_name = u->phone_number;
10979 }
10980 if (u->first_name != first_name || u->last_name != last_name) {
10981 u->first_name = std::move(first_name);
10982 u->last_name = std::move(last_name);
10983 u->is_name_changed = true;
10984 LOG(DEBUG) << "Name has changed for " << user_id;
10985 u->is_changed = true;
10986 }
10987 td_->messages_manager_->on_dialog_username_updated(DialogId(user_id), u->username, username);
10988 if (u->username != username) {
10989 u->username = std::move(username);
10990 u->is_username_changed = true;
10991 LOG(DEBUG) << "Username has changed for " << user_id;
10992 u->is_changed = true;
10993 }
10994 }
10995
on_update_user_phone_number(UserId user_id,string && phone_number)10996 void ContactsManager::on_update_user_phone_number(UserId user_id, string &&phone_number) {
10997 if (!user_id.is_valid()) {
10998 LOG(ERROR) << "Receive invalid " << user_id;
10999 return;
11000 }
11001
11002 User *u = get_user_force(user_id);
11003 if (u != nullptr) {
11004 on_update_user_phone_number(u, user_id, std::move(phone_number));
11005 update_user(u, user_id);
11006 } else {
11007 LOG(INFO) << "Ignore update user phone number about unknown " << user_id;
11008 }
11009 }
11010
on_update_user_phone_number(User * u,UserId user_id,string && phone_number)11011 void ContactsManager::on_update_user_phone_number(User *u, UserId user_id, string &&phone_number) {
11012 if (u->phone_number != phone_number) {
11013 u->phone_number = std::move(phone_number);
11014 LOG(DEBUG) << "Phone number has changed for " << user_id;
11015 u->is_changed = true;
11016 }
11017 }
11018
on_update_user_photo(UserId user_id,tl_object_ptr<telegram_api::UserProfilePhoto> && photo_ptr)11019 void ContactsManager::on_update_user_photo(UserId user_id, tl_object_ptr<telegram_api::UserProfilePhoto> &&photo_ptr) {
11020 if (!user_id.is_valid()) {
11021 LOG(ERROR) << "Receive invalid " << user_id;
11022 return;
11023 }
11024
11025 User *u = get_user_force(user_id);
11026 if (u != nullptr) {
11027 on_update_user_photo(u, user_id, std::move(photo_ptr), "on_update_user_photo");
11028 update_user(u, user_id);
11029 } else {
11030 LOG(INFO) << "Ignore update user photo about unknown " << user_id;
11031 }
11032 }
11033
on_update_user_photo(User * u,UserId user_id,tl_object_ptr<telegram_api::UserProfilePhoto> && photo,const char * source)11034 void ContactsManager::on_update_user_photo(User *u, UserId user_id,
11035 tl_object_ptr<telegram_api::UserProfilePhoto> &&photo, const char *source) {
11036 if (td_->auth_manager_->is_bot() && !G()->parameters().use_file_db && !u->is_photo_inited) {
11037 if (photo != nullptr && photo->get_id() == telegram_api::userProfilePhoto::ID) {
11038 auto *profile_photo = static_cast<telegram_api::userProfilePhoto *>(photo.get());
11039 if ((profile_photo->flags_ & telegram_api::userProfilePhoto::STRIPPED_THUMB_MASK) != 0) {
11040 profile_photo->flags_ -= telegram_api::userProfilePhoto::STRIPPED_THUMB_MASK;
11041 profile_photo->stripped_thumb_ = BufferSlice();
11042 }
11043 }
11044 auto &old_photo = pending_user_photos_[user_id];
11045 if (!LOG_IS_STRIPPED(ERROR) && to_string(old_photo) == to_string(photo)) {
11046 return;
11047 }
11048
11049 bool is_empty = photo == nullptr || photo->get_id() == telegram_api::userProfilePhotoEmpty::ID;
11050 old_photo = std::move(photo);
11051
11052 drop_user_photos(user_id, is_empty, true, "on_update_user_photo");
11053 return;
11054 }
11055
11056 do_update_user_photo(u, user_id, std::move(photo), source);
11057 }
11058
do_update_user_photo(User * u,UserId user_id,tl_object_ptr<telegram_api::UserProfilePhoto> && photo,const char * source)11059 void ContactsManager::do_update_user_photo(User *u, UserId user_id,
11060 tl_object_ptr<telegram_api::UserProfilePhoto> &&photo, const char *source) {
11061 ProfilePhoto new_photo = get_profile_photo(td_->file_manager_.get(), user_id, u->access_hash, std::move(photo));
11062 if (td_->auth_manager_->is_bot()) {
11063 new_photo.minithumbnail.clear();
11064 }
11065 do_update_user_photo(u, user_id, std::move(new_photo), true, source);
11066 }
11067
do_update_user_photo(User * u,UserId user_id,ProfilePhoto && new_photo,bool invalidate_photo_cache,const char * source)11068 void ContactsManager::do_update_user_photo(User *u, UserId user_id, ProfilePhoto &&new_photo,
11069 bool invalidate_photo_cache, const char *source) {
11070 u->is_photo_inited = true;
11071 if (new_photo != u->photo) {
11072 LOG_IF(ERROR, u->access_hash == -1 && new_photo.small_file_id.is_valid())
11073 << "Update profile photo of " << user_id << " without access hash from " << source;
11074 u->photo = new_photo;
11075 u->is_photo_changed = true;
11076 LOG(DEBUG) << "Photo has changed for " << user_id;
11077 u->is_changed = true;
11078
11079 if (invalidate_photo_cache) {
11080 drop_user_photos(user_id, u->photo.id <= 0, true, "do_update_user_photo");
11081 }
11082 }
11083 }
11084
register_user_photo(User * u,UserId user_id,const Photo & photo)11085 void ContactsManager::register_user_photo(User *u, UserId user_id, const Photo &photo) {
11086 auto photo_file_ids = photo_get_file_ids(photo);
11087 if (photo.is_empty() || photo_file_ids.empty()) {
11088 return;
11089 }
11090 auto first_file_id = photo_file_ids[0];
11091 auto file_type = td_->file_manager_->get_file_view(first_file_id).get_type();
11092 if (file_type == FileType::ProfilePhoto) {
11093 return;
11094 }
11095 CHECK(file_type == FileType::Photo);
11096 CHECK(u != nullptr);
11097 auto photo_id = photo.id.get();
11098 if (u->photo_ids.emplace(photo_id).second) {
11099 VLOG(file_references) << "Register photo " << photo_id << " of " << user_id;
11100 if (user_id == get_my_id()) {
11101 my_photo_file_id_[photo_id] = first_file_id;
11102 }
11103 FileSourceId file_source_id;
11104 auto it = user_profile_photo_file_source_ids_.find(std::make_pair(user_id, photo_id));
11105 if (it != user_profile_photo_file_source_ids_.end()) {
11106 VLOG(file_references) << "Move " << it->second << " inside of " << user_id;
11107 file_source_id = it->second;
11108 user_profile_photo_file_source_ids_.erase(it);
11109 } else {
11110 VLOG(file_references) << "Need to create new file source for photo " << photo_id << " of " << user_id;
11111 file_source_id = td_->file_reference_manager_->create_user_photo_file_source(user_id, photo_id);
11112 }
11113 for (auto &file_id : photo_file_ids) {
11114 td_->file_manager_->add_file_source(file_id, file_source_id);
11115 }
11116 }
11117 }
11118
on_update_user_is_contact(User * u,UserId user_id,bool is_contact,bool is_mutual_contact)11119 void ContactsManager::on_update_user_is_contact(User *u, UserId user_id, bool is_contact, bool is_mutual_contact) {
11120 UserId my_id = get_my_id();
11121 if (user_id == my_id) {
11122 is_mutual_contact = is_contact;
11123 }
11124 if (!is_contact && is_mutual_contact) {
11125 LOG(ERROR) << "Receive is_mutual_contact == true for non-contact " << user_id;
11126 is_mutual_contact = false;
11127 }
11128
11129 if (u->is_contact != is_contact || u->is_mutual_contact != is_mutual_contact) {
11130 LOG(DEBUG) << "Update " << user_id << " is_contact from (" << u->is_contact << ", " << u->is_mutual_contact
11131 << ") to (" << is_contact << ", " << is_mutual_contact << ")";
11132 if (u->is_contact != is_contact) {
11133 u->is_is_contact_changed = true;
11134 }
11135 u->is_contact = is_contact;
11136 u->is_mutual_contact = is_mutual_contact;
11137 u->is_changed = true;
11138 }
11139 }
11140
on_update_user_online(UserId user_id,tl_object_ptr<telegram_api::UserStatus> && status)11141 void ContactsManager::on_update_user_online(UserId user_id, tl_object_ptr<telegram_api::UserStatus> &&status) {
11142 if (!user_id.is_valid()) {
11143 LOG(ERROR) << "Receive invalid " << user_id;
11144 return;
11145 }
11146
11147 User *u = get_user_force(user_id);
11148 if (u != nullptr) {
11149 if (u->is_bot) {
11150 LOG(ERROR) << "Receive updateUserStatus about bot " << user_id;
11151 return;
11152 }
11153 on_update_user_online(u, user_id, std::move(status));
11154 update_user(u, user_id);
11155
11156 if (user_id == get_my_id() &&
11157 was_online_remote_ != u->was_online) { // only update was_online_remote_ from updateUserStatus
11158 was_online_remote_ = u->was_online;
11159 VLOG(notifications) << "Set was_online_remote to " << was_online_remote_;
11160 G()->td_db()->get_binlog_pmc()->set("my_was_online_remote", to_string(was_online_remote_));
11161 }
11162 } else {
11163 LOG(INFO) << "Ignore update user online about unknown " << user_id;
11164 }
11165 }
11166
on_update_user_online(User * u,UserId user_id,tl_object_ptr<telegram_api::UserStatus> && status)11167 void ContactsManager::on_update_user_online(User *u, UserId user_id, tl_object_ptr<telegram_api::UserStatus> &&status) {
11168 int32 id = status == nullptr ? telegram_api::userStatusEmpty::ID : status->get_id();
11169 int32 new_online;
11170 bool is_offline = false;
11171 if (id == telegram_api::userStatusOnline::ID) {
11172 int32 now = G()->unix_time();
11173
11174 auto st = move_tl_object_as<telegram_api::userStatusOnline>(status);
11175 new_online = st->expires_;
11176 LOG_IF(ERROR, new_online < now - 86400)
11177 << "Receive userStatusOnline expired more than one day in past " << new_online;
11178 } else if (id == telegram_api::userStatusOffline::ID) {
11179 int32 now = G()->unix_time();
11180
11181 auto st = move_tl_object_as<telegram_api::userStatusOffline>(status);
11182 new_online = st->was_online_;
11183 if (new_online >= now) {
11184 LOG_IF(ERROR, new_online > now + 10)
11185 << "Receive userStatusOffline but was online points to future time " << new_online << ", now is " << now;
11186 new_online = now - 1;
11187 }
11188 is_offline = true;
11189 } else if (id == telegram_api::userStatusRecently::ID) {
11190 new_online = -1;
11191 } else if (id == telegram_api::userStatusLastWeek::ID) {
11192 new_online = -2;
11193 is_offline = true;
11194 } else if (id == telegram_api::userStatusLastMonth::ID) {
11195 new_online = -3;
11196 is_offline = true;
11197 } else {
11198 CHECK(id == telegram_api::userStatusEmpty::ID);
11199 new_online = 0;
11200 }
11201
11202 if (new_online != u->was_online) {
11203 LOG(DEBUG) << "Update " << user_id << " online from " << u->was_online << " to " << new_online;
11204 bool old_is_online = u->was_online > G()->unix_time_cached();
11205 bool new_is_online = new_online > G()->unix_time_cached();
11206 u->was_online = new_online;
11207 u->is_status_changed = true;
11208 if (u->was_online > 0) {
11209 u->local_was_online = 0;
11210 }
11211
11212 if (user_id == get_my_id()) {
11213 if (my_was_online_local_ != 0 || old_is_online != new_is_online) {
11214 my_was_online_local_ = 0;
11215 u->is_online_status_changed = true;
11216 }
11217 if (is_offline) {
11218 td_->on_online_updated(false, false);
11219 }
11220 } else if (old_is_online != new_is_online) {
11221 u->is_online_status_changed = true;
11222 }
11223 }
11224 }
11225
on_update_user_local_was_online(UserId user_id,int32 local_was_online)11226 void ContactsManager::on_update_user_local_was_online(UserId user_id, int32 local_was_online) {
11227 CHECK(user_id.is_valid());
11228
11229 User *u = get_user_force(user_id);
11230 if (u == nullptr) {
11231 return;
11232 }
11233
11234 on_update_user_local_was_online(u, user_id, local_was_online);
11235 update_user(u, user_id);
11236 }
11237
on_update_user_local_was_online(User * u,UserId user_id,int32 local_was_online)11238 void ContactsManager::on_update_user_local_was_online(User *u, UserId user_id, int32 local_was_online) {
11239 CHECK(u != nullptr);
11240 if (u->is_deleted || u->is_bot || u->is_support || user_id == get_my_id()) {
11241 return;
11242 }
11243 if (u->was_online > G()->unix_time_cached()) {
11244 // if user is currently online, ignore local online
11245 return;
11246 }
11247
11248 // bring users online for 30 seconds
11249 local_was_online += 30;
11250 if (local_was_online < G()->unix_time_cached() + 2 || local_was_online <= u->local_was_online ||
11251 local_was_online <= u->was_online) {
11252 return;
11253 }
11254
11255 LOG(DEBUG) << "Update " << user_id << " local online from " << u->local_was_online << " to " << local_was_online;
11256 bool old_is_online = u->local_was_online > G()->unix_time_cached();
11257 u->local_was_online = local_was_online;
11258 u->is_status_changed = true;
11259
11260 if (!old_is_online) {
11261 u->is_online_status_changed = true;
11262 }
11263 }
11264
on_update_user_is_blocked(UserId user_id,bool is_blocked)11265 void ContactsManager::on_update_user_is_blocked(UserId user_id, bool is_blocked) {
11266 if (!user_id.is_valid()) {
11267 LOG(ERROR) << "Receive invalid " << user_id;
11268 return;
11269 }
11270
11271 UserFull *user_full = get_user_full_force(user_id);
11272 if (user_full == nullptr || user_full->is_blocked == is_blocked) {
11273 return;
11274 }
11275 on_update_user_full_is_blocked(user_full, user_id, is_blocked);
11276 update_user_full(user_full, user_id, "on_update_user_is_blocked");
11277 }
11278
on_update_user_full_is_blocked(UserFull * user_full,UserId user_id,bool is_blocked)11279 void ContactsManager::on_update_user_full_is_blocked(UserFull *user_full, UserId user_id, bool is_blocked) {
11280 CHECK(user_full != nullptr);
11281 if (user_full->is_blocked != is_blocked) {
11282 LOG(INFO) << "Receive update user full is blocked with " << user_id << " and is_blocked = " << is_blocked;
11283 user_full->is_blocked = is_blocked;
11284 user_full->is_changed = true;
11285 }
11286 }
11287
on_update_user_common_chat_count(UserId user_id,int32 common_chat_count)11288 void ContactsManager::on_update_user_common_chat_count(UserId user_id, int32 common_chat_count) {
11289 LOG(INFO) << "Receive " << common_chat_count << " common chat count with " << user_id;
11290 if (!user_id.is_valid()) {
11291 LOG(ERROR) << "Receive invalid " << user_id;
11292 return;
11293 }
11294
11295 UserFull *user_full = get_user_full_force(user_id);
11296 if (user_full == nullptr) {
11297 return;
11298 }
11299 on_update_user_full_common_chat_count(user_full, user_id, common_chat_count);
11300 update_user_full(user_full, user_id, "on_update_user_common_chat_count");
11301 }
11302
on_update_user_full_common_chat_count(UserFull * user_full,UserId user_id,int32 common_chat_count)11303 void ContactsManager::on_update_user_full_common_chat_count(UserFull *user_full, UserId user_id,
11304 int32 common_chat_count) {
11305 CHECK(user_full != nullptr);
11306 if (common_chat_count < 0) {
11307 LOG(ERROR) << "Receive " << common_chat_count << " as common group count with " << user_id;
11308 common_chat_count = 0;
11309 }
11310 if (user_full->common_chat_count != common_chat_count) {
11311 user_full->common_chat_count = common_chat_count;
11312 user_full->is_common_chat_count_changed = true;
11313 user_full->is_changed = true;
11314 }
11315 }
11316
on_update_user_full_commands(UserFull * user_full,UserId user_id,vector<tl_object_ptr<telegram_api::botCommand>> && bot_commands)11317 void ContactsManager::on_update_user_full_commands(UserFull *user_full, UserId user_id,
11318 vector<tl_object_ptr<telegram_api::botCommand>> &&bot_commands) {
11319 CHECK(user_full != nullptr);
11320 auto commands = transform(std::move(bot_commands), [](tl_object_ptr<telegram_api::botCommand> &&bot_command) {
11321 return BotCommand(std::move(bot_command));
11322 });
11323 if (user_full->commands != commands) {
11324 user_full->commands = std::move(commands);
11325 user_full->is_changed = true;
11326 }
11327 }
11328
on_update_user_need_phone_number_privacy_exception(UserId user_id,bool need_phone_number_privacy_exception)11329 void ContactsManager::on_update_user_need_phone_number_privacy_exception(UserId user_id,
11330 bool need_phone_number_privacy_exception) {
11331 LOG(INFO) << "Receive " << need_phone_number_privacy_exception << " need phone number privacy exception with "
11332 << user_id;
11333 if (!user_id.is_valid()) {
11334 LOG(ERROR) << "Receive invalid " << user_id;
11335 return;
11336 }
11337
11338 UserFull *user_full = get_user_full_force(user_id);
11339 if (user_full == nullptr) {
11340 return;
11341 }
11342 on_update_user_full_need_phone_number_privacy_exception(user_full, user_id, need_phone_number_privacy_exception);
11343 update_user_full(user_full, user_id, "on_update_user_need_phone_number_privacy_exception");
11344 }
11345
on_update_user_full_need_phone_number_privacy_exception(UserFull * user_full,UserId user_id,bool need_phone_number_privacy_exception) const11346 void ContactsManager::on_update_user_full_need_phone_number_privacy_exception(
11347 UserFull *user_full, UserId user_id, bool need_phone_number_privacy_exception) const {
11348 CHECK(user_full != nullptr);
11349 if (need_phone_number_privacy_exception) {
11350 const User *u = get_user(user_id);
11351 if (u == nullptr || u->is_contact || user_id == get_my_id()) {
11352 need_phone_number_privacy_exception = false;
11353 }
11354 }
11355 if (user_full->need_phone_number_privacy_exception != need_phone_number_privacy_exception) {
11356 user_full->need_phone_number_privacy_exception = need_phone_number_privacy_exception;
11357 user_full->is_changed = true;
11358 }
11359 }
11360
on_ignored_restriction_reasons_changed()11361 void ContactsManager::on_ignored_restriction_reasons_changed() {
11362 for (auto user_id : restricted_user_ids_) {
11363 send_closure(G()->td(), &Td::send_update,
11364 td_api::make_object<td_api::updateUser>(get_user_object(user_id, get_user(user_id))));
11365 }
11366 for (auto channel_id : restricted_channel_ids_) {
11367 send_closure(
11368 G()->td(), &Td::send_update,
11369 td_api::make_object<td_api::updateSupergroup>(get_supergroup_object(channel_id, get_channel(channel_id))));
11370 }
11371 }
11372
on_set_profile_photo(tl_object_ptr<telegram_api::photos_photo> && photo,int64 old_photo_id)11373 void ContactsManager::on_set_profile_photo(tl_object_ptr<telegram_api::photos_photo> &&photo, int64 old_photo_id) {
11374 LOG(INFO) << "Changed profile photo to " << to_string(photo);
11375
11376 UserId my_user_id = get_my_id();
11377
11378 if (old_photo_id != 0) {
11379 delete_profile_photo_from_cache(my_user_id, old_photo_id, false);
11380 }
11381
11382 add_profile_photo_to_cache(my_user_id,
11383 get_photo(td_->file_manager_.get(), std::move(photo->photo_), DialogId(my_user_id)));
11384
11385 // if cache was correctly updated, this should produce no updates
11386 on_get_users(std::move(photo->users_), "on_set_profile_photo");
11387 }
11388
on_delete_profile_photo(int64 profile_photo_id,Promise<Unit> promise)11389 void ContactsManager::on_delete_profile_photo(int64 profile_photo_id, Promise<Unit> promise) {
11390 UserId my_user_id = get_my_id();
11391
11392 bool need_reget_user = delete_profile_photo_from_cache(my_user_id, profile_photo_id, true);
11393 if (need_reget_user && !G()->close_flag()) {
11394 return reload_user(my_user_id, std::move(promise));
11395 }
11396
11397 promise.set_value(Unit());
11398 }
11399
add_profile_photo_to_cache(UserId user_id,Photo && photo)11400 void ContactsManager::add_profile_photo_to_cache(UserId user_id, Photo &&photo) {
11401 if (photo.is_empty()) {
11402 return;
11403 }
11404
11405 // we have subsequence of user photos in user_photos_
11406 // ProfilePhoto in User and Photo in UserFull
11407
11408 User *u = get_user_force(user_id);
11409 if (u == nullptr) {
11410 return;
11411 }
11412
11413 // update photo list
11414 auto it = user_photos_.find(user_id);
11415 if (it != user_photos_.end() && it->second.count != -1) {
11416 auto user_photos = &it->second;
11417 if (user_photos->offset == 0) {
11418 if (user_photos->photos.empty() || user_photos->photos[0].id.get() != photo.id.get()) {
11419 user_photos->photos.insert(user_photos->photos.begin(), photo);
11420 user_photos->count++;
11421 register_user_photo(u, user_id, user_photos->photos[0]);
11422 }
11423 } else {
11424 user_photos->count++;
11425 user_photos->offset++;
11426 }
11427 }
11428
11429 // update Photo in UserFull
11430 auto user_full = get_user_full_force(user_id);
11431 if (user_full != nullptr) {
11432 if (user_full->photo != photo) {
11433 user_full->photo = photo;
11434 user_full->is_changed = true;
11435 register_user_photo(u, user_id, photo);
11436 }
11437 update_user_full(user_full, user_id, "add_profile_photo_to_cache");
11438 }
11439
11440 // update ProfilePhoto in User
11441 do_update_user_photo(u, user_id, as_profile_photo(td_->file_manager_.get(), user_id, u->access_hash, photo), false,
11442 "add_profile_photo_to_cache");
11443 update_user(u, user_id);
11444 }
11445
delete_profile_photo_from_cache(UserId user_id,int64 profile_photo_id,bool send_updates)11446 bool ContactsManager::delete_profile_photo_from_cache(UserId user_id, int64 profile_photo_id, bool send_updates) {
11447 CHECK(profile_photo_id != 0);
11448
11449 // we have subsequence of user photos in user_photos_
11450 // ProfilePhoto in User and Photo in UserFull
11451
11452 User *u = get_user_force(user_id);
11453 bool is_main_photo_deleted = u != nullptr && u->photo.id == profile_photo_id;
11454
11455 // update photo list
11456 auto it = user_photos_.find(user_id);
11457 if (it != user_photos_.end() && it->second.count > 0) {
11458 auto user_photos = &it->second;
11459 auto old_size = user_photos->photos.size();
11460 if (td::remove_if(user_photos->photos,
11461 [profile_photo_id](const auto &photo) { return photo.id.get() == profile_photo_id; })) {
11462 auto removed_photos = old_size - user_photos->photos.size();
11463 CHECK(removed_photos > 0);
11464 LOG_IF(ERROR, removed_photos != 1) << "Had " << removed_photos << " photos with ID " << profile_photo_id;
11465 user_photos->count -= narrow_cast<int32>(removed_photos);
11466 // offset was not changed
11467 CHECK(user_photos->count >= 0);
11468 } else {
11469 // failed to find photo to remove from cache
11470 // don't know how to adjust user_photos->offset, so drop photos cache
11471 LOG(INFO) << "Drop photos of " << user_id;
11472 user_photos->photos.clear();
11473 user_photos->count = -1;
11474 user_photos->offset = -1;
11475 }
11476 }
11477
11478 // update Photo in UserFull
11479 auto user_full = get_user_full_force(user_id);
11480 if (user_full != nullptr && !user_full->photo.is_empty() &&
11481 (is_main_photo_deleted || user_full->photo.id.get() == profile_photo_id)) {
11482 if (it != user_photos_.end() && it->second.count != -1 && it->second.offset == 0 && !it->second.photos.empty()) {
11483 // found exact new photo
11484 if (it->second.photos[0] != user_full->photo) {
11485 user_full->photo = it->second.photos[0];
11486 user_full->is_changed = true;
11487 }
11488 } else {
11489 // repair UserFull photo
11490 user_full->expires_at = 0.0;
11491 user_full->photo = Photo();
11492 user_full->is_changed = true;
11493
11494 load_user_full(user_id, true, Auto(), "delete_profile_photo_from_cache");
11495 }
11496 if (send_updates) {
11497 update_user_full(user_full, user_id, "delete_profile_photo_from_cache");
11498 }
11499 }
11500
11501 // update ProfilePhoto in User
11502 if (is_main_photo_deleted) {
11503 bool need_reget_user = false;
11504 if (it != user_photos_.end() && it->second.count != -1 && it->second.offset == 0 && !it->second.photos.empty()) {
11505 // found exact new photo
11506 do_update_user_photo(u, user_id,
11507 as_profile_photo(td_->file_manager_.get(), user_id, u->access_hash, it->second.photos[0]),
11508 false, "delete_profile_photo_from_cache");
11509 } else {
11510 do_update_user_photo(u, user_id, ProfilePhoto(), false, "delete_profile_photo_from_cache 2");
11511 need_reget_user = it == user_photos_.end() || it->second.count != 0;
11512 }
11513 if (send_updates) {
11514 update_user(u, user_id);
11515 }
11516 return need_reget_user;
11517 }
11518
11519 return false;
11520 }
11521
drop_user_photos(UserId user_id,bool is_empty,bool drop_user_full_photo,const char * source)11522 void ContactsManager::drop_user_photos(UserId user_id, bool is_empty, bool drop_user_full_photo, const char *source) {
11523 auto it = user_photos_.find(user_id);
11524 if (it != user_photos_.end()) {
11525 auto user_photos = &it->second;
11526 int32 new_count = is_empty ? 0 : -1;
11527 if (user_photos->count == new_count) {
11528 CHECK(user_photos->photos.empty());
11529 CHECK(user_photos->offset == user_photos->count);
11530 return;
11531 }
11532
11533 LOG(INFO) << "Drop photos of " << user_id << " to " << (is_empty ? "empty" : "unknown") << " from " << source;
11534 user_photos->photos.clear();
11535 user_photos->count = new_count;
11536 user_photos->offset = user_photos->count;
11537 }
11538
11539 if (drop_user_full_photo) {
11540 auto user_full = get_user_full(user_id); // must not load UserFull
11541 if (user_full == nullptr) {
11542 return;
11543 }
11544
11545 if (!user_full->photo.is_empty()) {
11546 user_full->photo = Photo();
11547 user_full->is_changed = true;
11548 }
11549 if (!is_empty) {
11550 if (user_full->expires_at > 0.0) {
11551 user_full->expires_at = 0.0;
11552 user_full->need_save_to_database = true;
11553 }
11554 load_user_full(user_id, true, Auto(), "drop_user_photos");
11555 }
11556 update_user_full(user_full, user_id, "drop_user_photos");
11557 }
11558 }
11559
drop_user_full(UserId user_id)11560 void ContactsManager::drop_user_full(UserId user_id) {
11561 auto user_full = get_user_full_force(user_id);
11562
11563 drop_user_photos(user_id, false, false, "drop_user_full");
11564
11565 if (user_full == nullptr) {
11566 return;
11567 }
11568
11569 user_full->expires_at = 0.0;
11570
11571 user_full->photo = Photo();
11572 user_full->is_blocked = false;
11573 user_full->can_be_called = false;
11574 user_full->supports_video_calls = false;
11575 user_full->has_private_calls = false;
11576 user_full->need_phone_number_privacy_exception = false;
11577 user_full->about = string();
11578 user_full->description = string();
11579 user_full->commands.clear();
11580 user_full->common_chat_count = 0;
11581 user_full->private_forward_name.clear();
11582 user_full->is_changed = true;
11583
11584 update_user_full(user_full, user_id, "drop_user_full");
11585 td_->group_call_manager_->on_update_dialog_about(DialogId(user_id), user_full->about, true);
11586 }
11587
update_user_online_member_count(User * u)11588 void ContactsManager::update_user_online_member_count(User *u) {
11589 if (u->online_member_dialogs.empty()) {
11590 return;
11591 }
11592
11593 auto now = G()->unix_time_cached();
11594 vector<DialogId> expired_dialog_ids;
11595 for (auto &it : u->online_member_dialogs) {
11596 auto dialog_id = it.first;
11597 auto time = it.second;
11598 if (time < now - MessagesManager::ONLINE_MEMBER_COUNT_CACHE_EXPIRE_TIME) {
11599 expired_dialog_ids.push_back(dialog_id);
11600 continue;
11601 }
11602
11603 switch (dialog_id.get_type()) {
11604 case DialogType::Chat: {
11605 auto chat_id = dialog_id.get_chat_id();
11606 auto chat_full = get_chat_full(chat_id);
11607 CHECK(chat_full != nullptr);
11608 update_chat_online_member_count(chat_full, chat_id, false);
11609 break;
11610 }
11611 case DialogType::Channel: {
11612 auto channel_id = dialog_id.get_channel_id();
11613 update_channel_online_member_count(channel_id, false);
11614 break;
11615 }
11616 case DialogType::User:
11617 case DialogType::SecretChat:
11618 case DialogType::None:
11619 UNREACHABLE();
11620 break;
11621 }
11622 }
11623 for (auto &dialog_id : expired_dialog_ids) {
11624 u->online_member_dialogs.erase(dialog_id);
11625 if (dialog_id.get_type() == DialogType::Channel) {
11626 cached_channel_participants_.erase(dialog_id.get_channel_id());
11627 }
11628 }
11629 }
11630
update_chat_online_member_count(const ChatFull * chat_full,ChatId chat_id,bool is_from_server)11631 void ContactsManager::update_chat_online_member_count(const ChatFull *chat_full, ChatId chat_id, bool is_from_server) {
11632 update_dialog_online_member_count(chat_full->participants, DialogId(chat_id), is_from_server);
11633 }
11634
update_channel_online_member_count(ChannelId channel_id,bool is_from_server)11635 void ContactsManager::update_channel_online_member_count(ChannelId channel_id, bool is_from_server) {
11636 if (get_channel_type(channel_id) != ChannelType::Megagroup) {
11637 return;
11638 }
11639
11640 auto it = cached_channel_participants_.find(channel_id);
11641 if (it == cached_channel_participants_.end()) {
11642 return;
11643 }
11644 update_dialog_online_member_count(it->second, DialogId(channel_id), is_from_server);
11645 }
11646
update_dialog_online_member_count(const vector<DialogParticipant> & participants,DialogId dialog_id,bool is_from_server)11647 void ContactsManager::update_dialog_online_member_count(const vector<DialogParticipant> &participants,
11648 DialogId dialog_id, bool is_from_server) {
11649 if (td_->auth_manager_->is_bot()) {
11650 return;
11651 }
11652
11653 int32 online_member_count = 0;
11654 int32 time = G()->unix_time();
11655 for (const auto &participant : participants) {
11656 if (participant.dialog_id_.get_type() != DialogType::User) {
11657 continue;
11658 }
11659 auto user_id = participant.dialog_id_.get_user_id();
11660 auto u = get_user(user_id);
11661 if (u != nullptr && !u->is_deleted && !u->is_bot) {
11662 if (get_user_was_online(u, user_id) > time) {
11663 online_member_count++;
11664 }
11665 if (is_from_server) {
11666 u->online_member_dialogs[dialog_id] = time;
11667 }
11668 }
11669 }
11670 td_->messages_manager_->on_update_dialog_online_member_count(dialog_id, online_member_count, is_from_server);
11671 }
11672
on_get_chat_participants(tl_object_ptr<telegram_api::ChatParticipants> && participants_ptr,bool from_update)11673 void ContactsManager::on_get_chat_participants(tl_object_ptr<telegram_api::ChatParticipants> &&participants_ptr,
11674 bool from_update) {
11675 switch (participants_ptr->get_id()) {
11676 case telegram_api::chatParticipantsForbidden::ID: {
11677 auto participants = move_tl_object_as<telegram_api::chatParticipantsForbidden>(participants_ptr);
11678 ChatId chat_id(participants->chat_id_);
11679 if (!chat_id.is_valid()) {
11680 LOG(ERROR) << "Receive invalid " << chat_id;
11681 return;
11682 }
11683
11684 if (!have_chat_force(chat_id)) {
11685 LOG(ERROR) << chat_id << " not found";
11686 return;
11687 }
11688
11689 if (from_update) {
11690 drop_chat_full(chat_id);
11691 }
11692 break;
11693 }
11694 case telegram_api::chatParticipants::ID: {
11695 auto participants = move_tl_object_as<telegram_api::chatParticipants>(participants_ptr);
11696 ChatId chat_id(participants->chat_id_);
11697 if (!chat_id.is_valid()) {
11698 LOG(ERROR) << "Receive invalid " << chat_id;
11699 return;
11700 }
11701
11702 const Chat *c = get_chat_force(chat_id);
11703 if (c == nullptr) {
11704 LOG(ERROR) << chat_id << " not found";
11705 return;
11706 }
11707
11708 ChatFull *chat_full = get_chat_full_force(chat_id, "telegram_api::chatParticipants");
11709 if (chat_full == nullptr) {
11710 LOG(INFO) << "Ignore update of members for unknown full " << chat_id;
11711 return;
11712 }
11713
11714 UserId new_creator_user_id;
11715 vector<DialogParticipant> new_participants;
11716 new_participants.reserve(participants->participants_.size());
11717
11718 for (auto &participant_ptr : participants->participants_) {
11719 DialogParticipant dialog_participant(std::move(participant_ptr), c->date, c->status.is_creator());
11720 if (!dialog_participant.is_valid()) {
11721 LOG(ERROR) << "Receive invalid " << dialog_participant;
11722 continue;
11723 }
11724
11725 LOG_IF(ERROR, !td_->messages_manager_->have_dialog_info(dialog_participant.dialog_id_))
11726 << "Have no information about " << dialog_participant.dialog_id_ << " as a member of " << chat_id;
11727 LOG_IF(ERROR, !have_user(dialog_participant.inviter_user_id_))
11728 << "Have no information about " << dialog_participant.inviter_user_id_ << " as a member of " << chat_id;
11729 if (dialog_participant.joined_date_ < c->date) {
11730 LOG_IF(ERROR, dialog_participant.joined_date_ < c->date - 30 && c->date >= 1486000000)
11731 << "Wrong join date = " << dialog_participant.joined_date_ << " for " << dialog_participant.dialog_id_
11732 << ", " << chat_id << " was created at " << c->date;
11733 dialog_participant.joined_date_ = c->date;
11734 }
11735 if (dialog_participant.status_.is_creator() && dialog_participant.dialog_id_.get_type() == DialogType::User) {
11736 new_creator_user_id = dialog_participant.dialog_id_.get_user_id();
11737 }
11738 new_participants.push_back(std::move(dialog_participant));
11739 }
11740
11741 if (chat_full->creator_user_id != new_creator_user_id) {
11742 if (new_creator_user_id.is_valid() && chat_full->creator_user_id.is_valid()) {
11743 LOG(ERROR) << "Group creator has changed from " << chat_full->creator_user_id << " to " << new_creator_user_id
11744 << " in " << chat_id;
11745 }
11746 chat_full->creator_user_id = new_creator_user_id;
11747 chat_full->is_changed = true;
11748 }
11749
11750 on_update_chat_full_participants(chat_full, chat_id, std::move(new_participants), participants->version_,
11751 from_update);
11752 if (from_update) {
11753 update_chat_full(chat_full, chat_id, "on_get_chat_participants");
11754 }
11755 break;
11756 }
11757 default:
11758 UNREACHABLE();
11759 }
11760 }
11761
get_chat_participant(ChatId chat_id,UserId user_id) const11762 const DialogParticipant *ContactsManager::get_chat_participant(ChatId chat_id, UserId user_id) const {
11763 auto chat_full = get_chat_full(chat_id);
11764 if (chat_full == nullptr) {
11765 return nullptr;
11766 }
11767 return get_chat_full_participant(chat_full, DialogId(user_id));
11768 }
11769
get_chat_full_participant(const ChatFull * chat_full,DialogId dialog_id)11770 const DialogParticipant *ContactsManager::get_chat_full_participant(const ChatFull *chat_full, DialogId dialog_id) {
11771 for (const auto &dialog_participant : chat_full->participants) {
11772 if (dialog_participant.dialog_id_ == dialog_id) {
11773 return &dialog_participant;
11774 }
11775 }
11776 return nullptr;
11777 }
11778
get_chat_member_object(const DialogParticipant & dialog_participant) const11779 tl_object_ptr<td_api::chatMember> ContactsManager::get_chat_member_object(
11780 const DialogParticipant &dialog_participant) const {
11781 DialogId dialog_id = dialog_participant.dialog_id_;
11782 UserId participant_user_id;
11783 if (dialog_id.get_type() == DialogType::User) {
11784 participant_user_id = dialog_id.get_user_id();
11785 } else {
11786 td_->messages_manager_->force_create_dialog(dialog_id, "get_chat_member_object", true);
11787 }
11788 return td_api::make_object<td_api::chatMember>(
11789 get_message_sender_object_const(td_, dialog_id, "get_chat_member_object"),
11790 get_user_id_object(dialog_participant.inviter_user_id_, "chatMember.inviter_user_id"),
11791 dialog_participant.joined_date_, dialog_participant.status_.get_chat_member_status_object());
11792 }
11793
on_get_channel_error(ChannelId channel_id,const Status & status,const string & source)11794 bool ContactsManager::on_get_channel_error(ChannelId channel_id, const Status &status, const string &source) {
11795 LOG(INFO) << "Receive " << status << " in " << channel_id << " from " << source;
11796 if (status.message() == CSlice("BOT_METHOD_INVALID")) {
11797 LOG(ERROR) << "Receive BOT_METHOD_INVALID from " << source;
11798 return true;
11799 }
11800 if (G()->is_expected_error(status)) {
11801 return true;
11802 }
11803 if (status.message() == "CHANNEL_PRIVATE" || status.message() == "CHANNEL_PUBLIC_GROUP_NA") {
11804 if (!channel_id.is_valid()) {
11805 LOG(ERROR) << "Receive " << status.message() << " in invalid " << channel_id << " from " << source;
11806 return false;
11807 }
11808
11809 auto c = get_channel(channel_id);
11810 if (c == nullptr) {
11811 if (source == "GetChannelDifferenceQuery" || (td_->auth_manager_->is_bot() && source == "GetChannelsQuery")) {
11812 // get channel difference after restart
11813 // get channel from server by its identifier
11814 return true;
11815 }
11816 LOG(ERROR) << "Receive " << status.message() << " in not found " << channel_id << " from " << source;
11817 return false;
11818 }
11819
11820 auto debug_channel_object = oneline(to_string(get_supergroup_object(channel_id, c)));
11821 if (c->status.is_member()) {
11822 LOG(INFO) << "Emulate leaving " << channel_id;
11823 // TODO we also may try to write to a public channel
11824 int32 flags = 0;
11825 if (c->is_megagroup) {
11826 flags |= CHANNEL_FLAG_IS_MEGAGROUP;
11827 } else {
11828 flags |= CHANNEL_FLAG_IS_BROADCAST;
11829 }
11830 telegram_api::channelForbidden update(flags, false /*ignored*/, false /*ignored*/, channel_id.get(),
11831 c->access_hash, c->title, 0);
11832 on_chat_update(update, "CHANNEL_PRIVATE");
11833 } else if (!c->status.is_banned()) {
11834 if (!c->username.empty()) {
11835 LOG(INFO) << "Drop username of " << channel_id;
11836 on_update_channel_username(c, channel_id, "");
11837 }
11838
11839 on_update_channel_has_location(c, channel_id, false);
11840
11841 on_update_channel_linked_channel_id(channel_id, ChannelId());
11842
11843 update_channel(c, channel_id);
11844
11845 remove_dialog_access_by_invite_link(DialogId(channel_id));
11846 }
11847 invalidate_channel_full(channel_id, !c->is_slow_mode_enabled);
11848 LOG_IF(ERROR, have_input_peer_channel(c, channel_id, AccessRights::Read))
11849 << "Have read access to channel after receiving CHANNEL_PRIVATE. Channel state: "
11850 << oneline(to_string(get_supergroup_object(channel_id, c)))
11851 << ". Previous channel state: " << debug_channel_object;
11852
11853 return true;
11854 }
11855 return false;
11856 }
11857
is_user_contact(UserId user_id,bool is_mutual) const11858 bool ContactsManager::is_user_contact(UserId user_id, bool is_mutual) const {
11859 return is_user_contact(get_user(user_id), user_id, is_mutual);
11860 }
11861
is_user_contact(const User * u,UserId user_id,bool is_mutual) const11862 bool ContactsManager::is_user_contact(const User *u, UserId user_id, bool is_mutual) const {
11863 return u != nullptr && (is_mutual ? u->is_mutual_contact : u->is_contact) && user_id != get_my_id();
11864 }
11865
on_get_channel_participants(ChannelId channel_id,ChannelParticipantsFilter filter,int32 offset,int32 limit,string additional_query,int32 additional_limit,tl_object_ptr<telegram_api::channels_channelParticipants> && channel_participants,Promise<DialogParticipants> && promise)11866 void ContactsManager::on_get_channel_participants(
11867 ChannelId channel_id, ChannelParticipantsFilter filter, int32 offset, int32 limit, string additional_query,
11868 int32 additional_limit, tl_object_ptr<telegram_api::channels_channelParticipants> &&channel_participants,
11869 Promise<DialogParticipants> &&promise) {
11870 TRY_STATUS_PROMISE(promise, G()->close_status());
11871
11872 on_get_users(std::move(channel_participants->users_), "on_get_channel_participants");
11873 on_get_chats(std::move(channel_participants->chats_), "on_get_channel_participants");
11874 int32 total_count = channel_participants->count_;
11875 auto participants = std::move(channel_participants->participants_);
11876 LOG(INFO) << "Receive " << participants.size() << " " << filter << " members in " << channel_id;
11877
11878 bool is_full = offset == 0 && static_cast<int32>(participants.size()) < limit && total_count < limit;
11879
11880 vector<DialogParticipant> result;
11881 for (auto &participant_ptr : participants) {
11882 auto debug_participant = to_string(participant_ptr);
11883 result.emplace_back(std::move(participant_ptr));
11884 const auto &participant = result.back();
11885 UserId participant_user_id;
11886 if (participant.dialog_id_.get_type() == DialogType::User) {
11887 participant_user_id = participant.dialog_id_.get_user_id();
11888 }
11889 if (!participant.is_valid() || (filter.is_bots() && !is_user_bot(participant_user_id)) ||
11890 (filter.is_administrators() && !participant.status_.is_administrator()) ||
11891 ((filter.is_recent() || filter.is_contacts() || filter.is_search()) && !participant.status_.is_member()) ||
11892 (filter.is_contacts() && !is_user_contact(participant_user_id)) ||
11893 (filter.is_restricted() && !participant.status_.is_restricted()) ||
11894 (filter.is_banned() && !participant.status_.is_banned())) {
11895 bool skip_error = ((filter.is_administrators() || filter.is_bots()) && is_user_deleted(participant_user_id)) ||
11896 (filter.is_contacts() && participant_user_id == get_my_id());
11897 if (!skip_error) {
11898 LOG(ERROR) << "Receive " << participant << ", while searching for " << filter << " in " << channel_id
11899 << " with offset " << offset << " and limit " << limit << ": " << oneline(debug_participant);
11900 }
11901 result.pop_back();
11902 total_count--;
11903 }
11904 }
11905
11906 if (total_count < narrow_cast<int32>(result.size())) {
11907 LOG(ERROR) << "Receive total_count = " << total_count << ", but have at least " << result.size() << " " << filter
11908 << " members in " << channel_id;
11909 total_count = static_cast<int32>(result.size());
11910 } else if (is_full && total_count > static_cast<int32>(result.size())) {
11911 LOG(ERROR) << "Fix total number of " << filter << " members from " << total_count << " to " << result.size()
11912 << " in " << channel_id;
11913 total_count = static_cast<int32>(result.size());
11914 }
11915
11916 const auto max_participant_count = get_channel_type(channel_id) == ChannelType::Megagroup ? 975 : 195;
11917 auto participant_count =
11918 filter.is_recent() && total_count != 0 && total_count < max_participant_count ? total_count : -1;
11919 int32 administrator_count = filter.is_administrators() ? total_count : -1;
11920 if (is_full && (filter.is_administrators() || filter.is_bots() || filter.is_recent())) {
11921 vector<DialogAdministrator> administrators;
11922 vector<UserId> bot_user_ids;
11923 {
11924 if (filter.is_recent()) {
11925 for (const auto &participant : result) {
11926 if (participant.dialog_id_.get_type() == DialogType::User) {
11927 auto participant_user_id = participant.dialog_id_.get_user_id();
11928 if (participant.status_.is_administrator()) {
11929 administrators.emplace_back(participant_user_id, participant.status_.get_rank(),
11930 participant.status_.is_creator());
11931 }
11932 if (is_user_bot(participant_user_id)) {
11933 bot_user_ids.push_back(participant_user_id);
11934 }
11935 }
11936 }
11937 administrator_count = narrow_cast<int32>(administrators.size());
11938
11939 if (get_channel_type(channel_id) == ChannelType::Megagroup && !td_->auth_manager_->is_bot()) {
11940 cached_channel_participants_[channel_id] = result;
11941 update_channel_online_member_count(channel_id, true);
11942 }
11943 } else if (filter.is_administrators()) {
11944 for (const auto &participant : result) {
11945 if (participant.dialog_id_.get_type() == DialogType::User) {
11946 administrators.emplace_back(participant.dialog_id_.get_user_id(), participant.status_.get_rank(),
11947 participant.status_.is_creator());
11948 }
11949 }
11950 } else if (filter.is_bots()) {
11951 bot_user_ids = transform(result, [](const DialogParticipant &participant) {
11952 CHECK(participant.dialog_id_.get_type() == DialogType::User);
11953 return participant.dialog_id_.get_user_id();
11954 });
11955 }
11956 }
11957 if (filter.is_administrators() || filter.is_recent()) {
11958 on_update_dialog_administrators(DialogId(channel_id), std::move(administrators), true, false);
11959 }
11960 if (filter.is_bots() || filter.is_recent()) {
11961 on_update_channel_bot_user_ids(channel_id, std::move(bot_user_ids));
11962 }
11963 }
11964 if (have_channel_participant_cache(channel_id)) {
11965 for (const auto &participant : result) {
11966 add_channel_participant_to_cache(channel_id, participant, false);
11967 }
11968 }
11969
11970 if (participant_count != -1 || administrator_count != -1) {
11971 auto channel_full = get_channel_full_force(channel_id, true, "on_get_channel_participants_success");
11972 if (channel_full != nullptr) {
11973 if (administrator_count == -1) {
11974 administrator_count = channel_full->administrator_count;
11975 }
11976 if (participant_count == -1) {
11977 participant_count = channel_full->participant_count;
11978 }
11979 if (participant_count < administrator_count) {
11980 participant_count = administrator_count;
11981 }
11982 if (channel_full->participant_count != participant_count) {
11983 channel_full->participant_count = participant_count;
11984 channel_full->is_changed = true;
11985 }
11986 if (channel_full->administrator_count != administrator_count) {
11987 channel_full->administrator_count = administrator_count;
11988 channel_full->is_changed = true;
11989 }
11990 update_channel_full(channel_full, channel_id, "on_get_channel_participants");
11991 }
11992 if (participant_count != -1) {
11993 auto c = get_channel(channel_id);
11994 if (c != nullptr && c->participant_count != participant_count) {
11995 c->participant_count = participant_count;
11996 c->is_changed = true;
11997 update_channel(c, channel_id);
11998 }
11999 }
12000 }
12001
12002 if (!additional_query.empty()) {
12003 auto dialog_ids = transform(result, [](const DialogParticipant &participant) { return participant.dialog_id_; });
12004 std::pair<int32, vector<DialogId>> result_dialog_ids =
12005 search_among_dialogs(dialog_ids, additional_query, additional_limit);
12006
12007 total_count = result_dialog_ids.first;
12008 std::unordered_set<DialogId, DialogIdHash> result_dialog_ids_set(result_dialog_ids.second.begin(),
12009 result_dialog_ids.second.end());
12010 auto all_participants = std::move(result);
12011 result.clear();
12012 for (auto &participant : all_participants) {
12013 if (result_dialog_ids_set.count(participant.dialog_id_)) {
12014 result_dialog_ids_set.erase(participant.dialog_id_);
12015 result.push_back(std::move(participant));
12016 }
12017 }
12018 }
12019
12020 promise.set_value(DialogParticipants{total_count, std::move(result)});
12021 }
12022
have_channel_participant_cache(ChannelId channel_id) const12023 bool ContactsManager::have_channel_participant_cache(ChannelId channel_id) const {
12024 if (!td_->auth_manager_->is_bot()) {
12025 return false;
12026 }
12027 auto c = get_channel(channel_id);
12028 return c != nullptr && c->status.is_administrator();
12029 }
12030
add_channel_participant_to_cache(ChannelId channel_id,const DialogParticipant & dialog_participant,bool allow_replace)12031 void ContactsManager::add_channel_participant_to_cache(ChannelId channel_id,
12032 const DialogParticipant &dialog_participant,
12033 bool allow_replace) {
12034 auto &participants = channel_participants_[channel_id];
12035 if (participants.participants_.empty()) {
12036 channel_participant_cache_timeout_.set_timeout_in(channel_id.get(), CHANNEL_PARTICIPANT_CACHE_TIME);
12037 }
12038 auto &participant_info = participants.participants_[dialog_participant.dialog_id_];
12039 if (participant_info.last_access_date_ > 0 && !allow_replace) {
12040 return;
12041 }
12042 participant_info.participant_ = dialog_participant;
12043 participant_info.last_access_date_ = G()->unix_time();
12044 }
12045
get_channel_participant_from_cache(ChannelId channel_id,DialogId participant_dialog_id)12046 const DialogParticipant *ContactsManager::get_channel_participant_from_cache(ChannelId channel_id,
12047 DialogId participant_dialog_id) {
12048 auto channel_participants_it = channel_participants_.find(channel_id);
12049 if (channel_participants_it == channel_participants_.end()) {
12050 return nullptr;
12051 }
12052
12053 auto &participants = channel_participants_it->second.participants_;
12054 CHECK(!participants.empty());
12055 auto it = participants.find(participant_dialog_id);
12056 if (it != participants.end()) {
12057 it->second.participant_.status_.update_restrictions();
12058 it->second.last_access_date_ = G()->unix_time();
12059 return &it->second.participant_;
12060 }
12061 return nullptr;
12062 }
12063
speculative_add_count(int32 & count,int32 delta_count,int32 min_count)12064 bool ContactsManager::speculative_add_count(int32 &count, int32 delta_count, int32 min_count) {
12065 auto new_count = count + delta_count;
12066 if (new_count < min_count) {
12067 new_count = min_count;
12068 }
12069 if (new_count == count) {
12070 return false;
12071 }
12072
12073 count = new_count;
12074 return true;
12075 }
12076
speculative_add_channel_participants(ChannelId channel_id,const vector<UserId> & added_user_ids,UserId inviter_user_id,int32 date,bool by_me)12077 void ContactsManager::speculative_add_channel_participants(ChannelId channel_id, const vector<UserId> &added_user_ids,
12078 UserId inviter_user_id, int32 date, bool by_me) {
12079 auto it = cached_channel_participants_.find(channel_id);
12080 auto channel_full = get_channel_full_force(channel_id, true, "speculative_add_channel_participants");
12081 bool is_participants_cache_changed = false;
12082
12083 int32 delta_participant_count = 0;
12084 for (auto user_id : added_user_ids) {
12085 if (!user_id.is_valid()) {
12086 continue;
12087 }
12088
12089 delta_participant_count++;
12090
12091 if (it != cached_channel_participants_.end()) {
12092 auto &participants = it->second;
12093 bool is_found = false;
12094 for (auto &participant : participants) {
12095 if (participant.dialog_id_ == DialogId(user_id)) {
12096 is_found = true;
12097 break;
12098 }
12099 }
12100 if (!is_found) {
12101 is_participants_cache_changed = true;
12102 participants.emplace_back(DialogId(user_id), inviter_user_id, date, DialogParticipantStatus::Member());
12103 }
12104 }
12105
12106 if (channel_full != nullptr && is_user_bot(user_id) && !td::contains(channel_full->bot_user_ids, user_id)) {
12107 channel_full->bot_user_ids.push_back(user_id);
12108 channel_full->need_save_to_database = true;
12109 reload_channel_full(channel_id, Promise<Unit>(), "speculative_add_channel_participants");
12110
12111 send_closure_later(G()->messages_manager(), &MessagesManager::on_dialog_bots_updated, DialogId(channel_id),
12112 channel_full->bot_user_ids, false);
12113 }
12114 }
12115 if (is_participants_cache_changed) {
12116 update_channel_online_member_count(channel_id, false);
12117 }
12118 if (channel_full != nullptr) {
12119 update_channel_full(channel_full, channel_id, "speculative_add_channel_participants");
12120 }
12121 if (delta_participant_count == 0) {
12122 return;
12123 }
12124
12125 speculative_add_channel_participant_count(channel_id, delta_participant_count, by_me);
12126 }
12127
speculative_delete_channel_participant(ChannelId channel_id,UserId deleted_user_id,bool by_me)12128 void ContactsManager::speculative_delete_channel_participant(ChannelId channel_id, UserId deleted_user_id, bool by_me) {
12129 if (!deleted_user_id.is_valid()) {
12130 return;
12131 }
12132
12133 auto it = cached_channel_participants_.find(channel_id);
12134 if (it != cached_channel_participants_.end()) {
12135 auto &participants = it->second;
12136 for (size_t i = 0; i < participants.size(); i++) {
12137 if (participants[i].dialog_id_ == DialogId(deleted_user_id)) {
12138 participants.erase(participants.begin() + i);
12139 update_channel_online_member_count(channel_id, false);
12140 break;
12141 }
12142 }
12143 }
12144
12145 if (is_user_bot(deleted_user_id)) {
12146 auto channel_full = get_channel_full_force(channel_id, true, "speculative_delete_channel_participant");
12147 if (channel_full != nullptr && td::remove(channel_full->bot_user_ids, deleted_user_id)) {
12148 channel_full->need_save_to_database = true;
12149 update_channel_full(channel_full, channel_id, "speculative_delete_channel_participant");
12150
12151 send_closure_later(G()->messages_manager(), &MessagesManager::on_dialog_bots_updated, DialogId(channel_id),
12152 channel_full->bot_user_ids, false);
12153 }
12154 }
12155
12156 speculative_add_channel_participant_count(channel_id, -1, by_me);
12157 }
12158
speculative_add_channel_participant_count(ChannelId channel_id,int32 delta_participant_count,bool by_me)12159 void ContactsManager::speculative_add_channel_participant_count(ChannelId channel_id, int32 delta_participant_count,
12160 bool by_me) {
12161 if (by_me) {
12162 // Currently ignore all changes made by the current user, because they may be already counted
12163 invalidate_channel_full(channel_id, false); // just in case
12164 return;
12165 }
12166
12167 auto channel_full = get_channel_full_force(channel_id, true, "speculative_add_channel_participant_count");
12168 auto min_count = channel_full == nullptr ? 0 : channel_full->administrator_count;
12169
12170 auto c = get_channel_force(channel_id);
12171 if (c != nullptr && c->participant_count != 0 &&
12172 speculative_add_count(c->participant_count, delta_participant_count, min_count)) {
12173 c->is_changed = true;
12174 update_channel(c, channel_id);
12175 }
12176
12177 if (channel_full == nullptr) {
12178 return;
12179 }
12180
12181 channel_full->is_changed |=
12182 speculative_add_count(channel_full->participant_count, delta_participant_count, min_count);
12183
12184 if (channel_full->is_changed) {
12185 channel_full->speculative_version++;
12186 }
12187
12188 update_channel_full(channel_full, channel_id, "speculative_add_channel_participant_count");
12189 }
12190
speculative_add_channel_user(ChannelId channel_id,UserId user_id,const DialogParticipantStatus & new_status,const DialogParticipantStatus & old_status)12191 void ContactsManager::speculative_add_channel_user(ChannelId channel_id, UserId user_id,
12192 const DialogParticipantStatus &new_status,
12193 const DialogParticipantStatus &old_status) {
12194 auto c = get_channel_force(channel_id);
12195 // channel full must be loaded before c->participant_count is updated, because on_load_channel_full_from_database
12196 // must copy the initial c->participant_count before it is speculatibely updated
12197 auto channel_full = get_channel_full_force(channel_id, true, "speculative_add_channel_user");
12198 int32 min_count = 0;
12199 if (channel_full != nullptr) {
12200 channel_full->is_changed |= speculative_add_count(channel_full->administrator_count,
12201 new_status.is_administrator() - old_status.is_administrator());
12202 min_count = channel_full->administrator_count;
12203 }
12204
12205 if (c != nullptr && c->participant_count != 0 &&
12206 speculative_add_count(c->participant_count, new_status.is_member() - old_status.is_member(), min_count)) {
12207 c->is_changed = true;
12208 update_channel(c, channel_id);
12209 }
12210
12211 if (new_status.is_administrator() != old_status.is_administrator() ||
12212 new_status.get_rank() != old_status.get_rank()) {
12213 DialogId dialog_id(channel_id);
12214 auto administrators_it = dialog_administrators_.find(dialog_id);
12215 if (administrators_it != dialog_administrators_.end()) {
12216 auto administrators = administrators_it->second;
12217 if (new_status.is_administrator()) {
12218 bool is_found = false;
12219 for (auto &administrator : administrators) {
12220 if (administrator.get_user_id() == user_id) {
12221 is_found = true;
12222 if (administrator.get_rank() != new_status.get_rank() ||
12223 administrator.is_creator() != new_status.is_creator()) {
12224 administrator = DialogAdministrator(user_id, new_status.get_rank(), new_status.is_creator());
12225 on_update_dialog_administrators(dialog_id, std::move(administrators), true, false);
12226 }
12227 break;
12228 }
12229 }
12230 if (!is_found) {
12231 administrators.emplace_back(user_id, new_status.get_rank(), new_status.is_creator());
12232 on_update_dialog_administrators(dialog_id, std::move(administrators), true, false);
12233 }
12234 } else {
12235 size_t i = 0;
12236 while (i != administrators.size() && administrators[i].get_user_id() != user_id) {
12237 i++;
12238 }
12239 if (i != administrators.size()) {
12240 administrators.erase(administrators.begin() + i);
12241 on_update_dialog_administrators(dialog_id, std::move(administrators), true, false);
12242 }
12243 }
12244 }
12245 }
12246
12247 auto it = cached_channel_participants_.find(channel_id);
12248 if (it != cached_channel_participants_.end()) {
12249 auto &participants = it->second;
12250 bool is_found = false;
12251 for (size_t i = 0; i < participants.size(); i++) {
12252 if (participants[i].dialog_id_ == DialogId(user_id)) {
12253 if (!new_status.is_member()) {
12254 participants.erase(participants.begin() + i);
12255 update_channel_online_member_count(channel_id, false);
12256 } else {
12257 participants[i].status_ = new_status;
12258 }
12259 is_found = true;
12260 break;
12261 }
12262 }
12263 if (!is_found && new_status.is_member()) {
12264 participants.emplace_back(DialogId(user_id), get_my_id(), G()->unix_time(), new_status);
12265 update_channel_online_member_count(channel_id, false);
12266 }
12267 }
12268
12269 if (channel_full == nullptr) {
12270 return;
12271 }
12272
12273 channel_full->is_changed |= speculative_add_count(channel_full->participant_count,
12274 new_status.is_member() - old_status.is_member(), min_count);
12275 channel_full->is_changed |=
12276 speculative_add_count(channel_full->restricted_count, new_status.is_restricted() - old_status.is_restricted());
12277 channel_full->is_changed |=
12278 speculative_add_count(channel_full->banned_count, new_status.is_banned() - old_status.is_banned());
12279
12280 if (channel_full->is_changed) {
12281 channel_full->speculative_version++;
12282 }
12283
12284 if (new_status.is_member() != old_status.is_member() && is_user_bot(user_id)) {
12285 if (new_status.is_member()) {
12286 if (!td::contains(channel_full->bot_user_ids, user_id)) {
12287 channel_full->bot_user_ids.push_back(user_id);
12288 channel_full->need_save_to_database = true;
12289 reload_channel_full(channel_id, Promise<Unit>(), "speculative_add_channel_user");
12290
12291 send_closure_later(G()->messages_manager(), &MessagesManager::on_dialog_bots_updated, DialogId(channel_id),
12292 channel_full->bot_user_ids, false);
12293 }
12294 } else {
12295 if (td::remove(channel_full->bot_user_ids, user_id)) {
12296 channel_full->need_save_to_database = true;
12297
12298 send_closure_later(G()->messages_manager(), &MessagesManager::on_dialog_bots_updated, DialogId(channel_id),
12299 channel_full->bot_user_ids, false);
12300 }
12301 }
12302 }
12303
12304 update_channel_full(channel_full, channel_id, "speculative_add_channel_user");
12305 }
12306
drop_channel_photos(ChannelId channel_id,bool is_empty,bool drop_channel_full_photo,const char * source)12307 void ContactsManager::drop_channel_photos(ChannelId channel_id, bool is_empty, bool drop_channel_full_photo,
12308 const char *source) {
12309 if (drop_channel_full_photo) {
12310 auto channel_full = get_channel_full(channel_id, true, "drop_channel_photos"); // must not load ChannelFull
12311 if (channel_full == nullptr) {
12312 return;
12313 }
12314
12315 on_update_channel_full_photo(channel_full, channel_id, Photo());
12316 if (!is_empty) {
12317 if (channel_full->expires_at > 0.0) {
12318 channel_full->expires_at = 0.0;
12319 channel_full->need_save_to_database = true;
12320 }
12321 send_get_channel_full_query(channel_full, channel_id, Auto(), "drop_channel_photos");
12322 }
12323 update_channel_full(channel_full, channel_id, "drop_channel_photos");
12324 }
12325 }
12326
invalidate_channel_full(ChannelId channel_id,bool need_drop_slow_mode_delay)12327 void ContactsManager::invalidate_channel_full(ChannelId channel_id, bool need_drop_slow_mode_delay) {
12328 LOG(INFO) << "Invalidate supergroup full for " << channel_id;
12329 auto channel_full = get_channel_full(channel_id, true, "invalidate_channel_full"); // must not load ChannelFull
12330 if (channel_full != nullptr) {
12331 do_invalidate_channel_full(channel_full, channel_id, need_drop_slow_mode_delay);
12332 update_channel_full(channel_full, channel_id, "invalidate_channel_full");
12333 } else {
12334 invalidated_channels_full_.insert(channel_id);
12335 }
12336 }
12337
do_invalidate_channel_full(ChannelFull * channel_full,ChannelId channel_id,bool need_drop_slow_mode_delay)12338 void ContactsManager::do_invalidate_channel_full(ChannelFull *channel_full, ChannelId channel_id,
12339 bool need_drop_slow_mode_delay) {
12340 CHECK(channel_full != nullptr);
12341 td_->messages_manager_->on_dialog_info_full_invalidated(DialogId(channel_id));
12342 if (channel_full->expires_at >= Time::now()) {
12343 channel_full->expires_at = 0.0;
12344 channel_full->need_save_to_database = true;
12345 }
12346 if (need_drop_slow_mode_delay && channel_full->slow_mode_delay != 0) {
12347 channel_full->slow_mode_delay = 0;
12348 channel_full->slow_mode_next_send_date = 0;
12349 channel_full->is_slow_mode_next_send_date_changed = true;
12350 channel_full->is_changed = true;
12351 }
12352 }
12353
on_update_chat_full_photo(ChatFull * chat_full,ChatId chat_id,Photo photo)12354 void ContactsManager::on_update_chat_full_photo(ChatFull *chat_full, ChatId chat_id, Photo photo) {
12355 CHECK(chat_full != nullptr);
12356 if (photo != chat_full->photo) {
12357 chat_full->photo = std::move(photo);
12358 chat_full->is_changed = true;
12359 }
12360 if (chat_full->photo.is_empty()) {
12361 drop_chat_photos(chat_id, true, false, "on_update_chat_full_photo");
12362 }
12363
12364 auto photo_file_ids = photo_get_file_ids(chat_full->photo);
12365 if (chat_full->registered_photo_file_ids == photo_file_ids) {
12366 return;
12367 }
12368
12369 auto &file_source_id = chat_full->file_source_id;
12370 if (!file_source_id.is_valid()) {
12371 auto it = chat_full_file_source_ids_.find(chat_id);
12372 if (it != chat_full_file_source_ids_.end()) {
12373 VLOG(file_references) << "Move " << it->second << " inside of " << chat_id;
12374 file_source_id = it->second;
12375 chat_full_file_source_ids_.erase(it);
12376 } else {
12377 VLOG(file_references) << "Need to create new file source for full " << chat_id;
12378 file_source_id = td_->file_reference_manager_->create_chat_full_file_source(chat_id);
12379 }
12380 }
12381
12382 for (auto &file_id : chat_full->registered_photo_file_ids) {
12383 td_->file_manager_->remove_file_source(file_id, file_source_id);
12384 }
12385 chat_full->registered_photo_file_ids = std::move(photo_file_ids);
12386 for (auto &file_id : chat_full->registered_photo_file_ids) {
12387 td_->file_manager_->add_file_source(file_id, file_source_id);
12388 }
12389 }
12390
on_update_channel_full_photo(ChannelFull * channel_full,ChannelId channel_id,Photo photo)12391 void ContactsManager::on_update_channel_full_photo(ChannelFull *channel_full, ChannelId channel_id, Photo photo) {
12392 CHECK(channel_full != nullptr);
12393 if (photo != channel_full->photo) {
12394 channel_full->photo = std::move(photo);
12395 channel_full->is_changed = true;
12396 }
12397 if (channel_full->photo.is_empty()) {
12398 drop_channel_photos(channel_id, true, false, "on_update_channel_full_photo");
12399 }
12400
12401 auto photo_file_ids = photo_get_file_ids(channel_full->photo);
12402 if (channel_full->registered_photo_file_ids == photo_file_ids) {
12403 return;
12404 }
12405
12406 auto &file_source_id = channel_full->file_source_id;
12407 if (!file_source_id.is_valid()) {
12408 auto it = channel_full_file_source_ids_.find(channel_id);
12409 if (it != channel_full_file_source_ids_.end()) {
12410 VLOG(file_references) << "Move " << it->second << " inside of " << channel_id;
12411 file_source_id = it->second;
12412 channel_full_file_source_ids_.erase(it);
12413 } else {
12414 VLOG(file_references) << "Need to create new file source for full " << channel_id;
12415 file_source_id = td_->file_reference_manager_->create_channel_full_file_source(channel_id);
12416 }
12417 }
12418
12419 for (auto &file_id : channel_full->registered_photo_file_ids) {
12420 td_->file_manager_->remove_file_source(file_id, file_source_id);
12421 }
12422 channel_full->registered_photo_file_ids = std::move(photo_file_ids);
12423 for (auto &file_id : channel_full->registered_photo_file_ids) {
12424 td_->file_manager_->add_file_source(file_id, file_source_id);
12425 }
12426 }
12427
on_get_permanent_dialog_invite_link(DialogId dialog_id,const DialogInviteLink & invite_link)12428 void ContactsManager::on_get_permanent_dialog_invite_link(DialogId dialog_id, const DialogInviteLink &invite_link) {
12429 switch (dialog_id.get_type()) {
12430 case DialogType::Chat: {
12431 auto chat_id = dialog_id.get_chat_id();
12432 auto chat_full = get_chat_full_force(chat_id, "on_get_permanent_dialog_invite_link");
12433 if (chat_full != nullptr && update_permanent_invite_link(chat_full->invite_link, invite_link)) {
12434 chat_full->is_changed = true;
12435 update_chat_full(chat_full, chat_id, "on_get_permanent_dialog_invite_link");
12436 }
12437 break;
12438 }
12439 case DialogType::Channel: {
12440 auto channel_id = dialog_id.get_channel_id();
12441 auto channel_full = get_channel_full_force(channel_id, true, "on_get_permanent_dialog_invite_link");
12442 if (channel_full != nullptr && update_permanent_invite_link(channel_full->invite_link, invite_link)) {
12443 channel_full->is_changed = true;
12444 update_channel_full(channel_full, channel_id, "on_get_permanent_dialog_invite_link");
12445 }
12446 break;
12447 }
12448 case DialogType::User:
12449 case DialogType::SecretChat:
12450 case DialogType::None:
12451 default:
12452 UNREACHABLE();
12453 }
12454 }
12455
on_update_chat_full_invite_link(ChatFull * chat_full,tl_object_ptr<telegram_api::chatInviteExported> && invite_link)12456 void ContactsManager::on_update_chat_full_invite_link(ChatFull *chat_full,
12457 tl_object_ptr<telegram_api::chatInviteExported> &&invite_link) {
12458 CHECK(chat_full != nullptr);
12459 if (update_permanent_invite_link(chat_full->invite_link, DialogInviteLink(std::move(invite_link)))) {
12460 chat_full->is_changed = true;
12461 }
12462 }
12463
on_update_channel_full_invite_link(ChannelFull * channel_full,tl_object_ptr<telegram_api::chatInviteExported> && invite_link)12464 void ContactsManager::on_update_channel_full_invite_link(
12465 ChannelFull *channel_full, tl_object_ptr<telegram_api::chatInviteExported> &&invite_link) {
12466 CHECK(channel_full != nullptr);
12467 if (update_permanent_invite_link(channel_full->invite_link, DialogInviteLink(std::move(invite_link)))) {
12468 channel_full->is_changed = true;
12469 }
12470 }
12471
remove_linked_channel_id(ChannelId channel_id)12472 void ContactsManager::remove_linked_channel_id(ChannelId channel_id) {
12473 if (!channel_id.is_valid()) {
12474 return;
12475 }
12476
12477 auto it = linked_channel_ids_.find(channel_id);
12478 if (it != linked_channel_ids_.end()) {
12479 auto linked_channel_id = it->second;
12480 linked_channel_ids_.erase(it);
12481 linked_channel_ids_.erase(linked_channel_id);
12482 }
12483 }
12484
get_linked_channel_id(ChannelId channel_id) const12485 ChannelId ContactsManager::get_linked_channel_id(ChannelId channel_id) const {
12486 auto channel_full = get_channel_full(channel_id);
12487 if (channel_full != nullptr) {
12488 return channel_full->linked_channel_id;
12489 }
12490
12491 auto it = linked_channel_ids_.find(channel_id);
12492 if (it != linked_channel_ids_.end()) {
12493 return it->second;
12494 }
12495
12496 return ChannelId();
12497 }
12498
on_update_channel_full_linked_channel_id(ChannelFull * channel_full,ChannelId channel_id,ChannelId linked_channel_id)12499 void ContactsManager::on_update_channel_full_linked_channel_id(ChannelFull *channel_full, ChannelId channel_id,
12500 ChannelId linked_channel_id) {
12501 auto old_linked_channel_id = get_linked_channel_id(channel_id);
12502 LOG(INFO) << "Uplate linked channel in " << channel_id << " from " << old_linked_channel_id << " to "
12503 << linked_channel_id;
12504
12505 if (channel_full != nullptr && channel_full->linked_channel_id != linked_channel_id &&
12506 channel_full->linked_channel_id.is_valid()) {
12507 get_channel_force(channel_full->linked_channel_id);
12508 get_channel_full_force(channel_full->linked_channel_id, true, "on_update_channel_full_linked_channel_id 0");
12509 }
12510 auto old_linked_linked_channel_id = get_linked_channel_id(linked_channel_id);
12511
12512 remove_linked_channel_id(channel_id);
12513 remove_linked_channel_id(linked_channel_id);
12514 if (channel_id.is_valid() && linked_channel_id.is_valid()) {
12515 linked_channel_ids_[channel_id] = linked_channel_id;
12516 linked_channel_ids_[linked_channel_id] = channel_id;
12517 }
12518
12519 if (channel_full != nullptr && channel_full->linked_channel_id != linked_channel_id) {
12520 if (channel_full->linked_channel_id.is_valid()) {
12521 // remove link from a previously linked channel_full
12522 auto linked_channel = get_channel_force(channel_full->linked_channel_id);
12523 if (linked_channel != nullptr && linked_channel->has_linked_channel) {
12524 linked_channel->has_linked_channel = false;
12525 linked_channel->is_changed = true;
12526 update_channel(linked_channel, channel_full->linked_channel_id);
12527 reload_channel(channel_full->linked_channel_id, Auto());
12528 }
12529 auto linked_channel_full =
12530 get_channel_full_force(channel_full->linked_channel_id, true, "on_update_channel_full_linked_channel_id 1");
12531 if (linked_channel_full != nullptr && linked_channel_full->linked_channel_id == channel_id) {
12532 linked_channel_full->linked_channel_id = ChannelId();
12533 linked_channel_full->is_changed = true;
12534 update_channel_full(linked_channel_full, channel_full->linked_channel_id,
12535 "on_update_channel_full_linked_channel_id 3");
12536 }
12537 }
12538
12539 channel_full->linked_channel_id = linked_channel_id;
12540 channel_full->is_changed = true;
12541
12542 if (channel_full->linked_channel_id.is_valid()) {
12543 // add link from a newly linked channel_full
12544 auto linked_channel = get_channel_force(channel_full->linked_channel_id);
12545 if (linked_channel != nullptr && !linked_channel->has_linked_channel) {
12546 linked_channel->has_linked_channel = true;
12547 linked_channel->is_changed = true;
12548 update_channel(linked_channel, channel_full->linked_channel_id);
12549 reload_channel(channel_full->linked_channel_id, Auto());
12550 }
12551 auto linked_channel_full =
12552 get_channel_full_force(channel_full->linked_channel_id, true, "on_update_channel_full_linked_channel_id 2");
12553 if (linked_channel_full != nullptr && linked_channel_full->linked_channel_id != channel_id) {
12554 linked_channel_full->linked_channel_id = channel_id;
12555 linked_channel_full->is_changed = true;
12556 update_channel_full(linked_channel_full, channel_full->linked_channel_id,
12557 "on_update_channel_full_linked_channel_id 4");
12558 }
12559 }
12560 }
12561
12562 Channel *c = get_channel(channel_id);
12563 CHECK(c != nullptr);
12564 if (linked_channel_id.is_valid() != c->has_linked_channel) {
12565 c->has_linked_channel = linked_channel_id.is_valid();
12566 c->is_changed = true;
12567 update_channel(c, channel_id);
12568 }
12569
12570 if (old_linked_channel_id != linked_channel_id) {
12571 // must be called after the linked channel is changed
12572 td_->messages_manager_->on_dialog_linked_channel_updated(DialogId(channel_id), old_linked_channel_id,
12573 linked_channel_id);
12574 }
12575
12576 if (linked_channel_id.is_valid()) {
12577 auto new_linked_linked_channel_id = get_linked_channel_id(linked_channel_id);
12578 LOG(INFO) << "Uplate linked channel in " << linked_channel_id << " from " << old_linked_linked_channel_id << " to "
12579 << new_linked_linked_channel_id;
12580 if (old_linked_linked_channel_id != new_linked_linked_channel_id) {
12581 // must be called after the linked channel is changed
12582 td_->messages_manager_->on_dialog_linked_channel_updated(
12583 DialogId(linked_channel_id), old_linked_linked_channel_id, new_linked_linked_channel_id);
12584 }
12585 }
12586 }
12587
on_update_channel_full_location(ChannelFull * channel_full,ChannelId channel_id,const DialogLocation & location)12588 void ContactsManager::on_update_channel_full_location(ChannelFull *channel_full, ChannelId channel_id,
12589 const DialogLocation &location) {
12590 if (channel_full->location != location) {
12591 channel_full->location = location;
12592 channel_full->is_changed = true;
12593 }
12594
12595 Channel *c = get_channel(channel_id);
12596 CHECK(c != nullptr);
12597 on_update_channel_has_location(c, channel_id, !location.empty());
12598 update_channel(c, channel_id);
12599 }
12600
on_update_channel_full_slow_mode_delay(ChannelFull * channel_full,ChannelId channel_id,int32 slow_mode_delay,int32 slow_mode_next_send_date)12601 void ContactsManager::on_update_channel_full_slow_mode_delay(ChannelFull *channel_full, ChannelId channel_id,
12602 int32 slow_mode_delay, int32 slow_mode_next_send_date) {
12603 if (slow_mode_delay < 0) {
12604 LOG(ERROR) << "Receive slow mode delay " << slow_mode_delay << " in " << channel_id;
12605 slow_mode_delay = 0;
12606 }
12607
12608 if (channel_full->slow_mode_delay != slow_mode_delay) {
12609 channel_full->slow_mode_delay = slow_mode_delay;
12610 channel_full->is_changed = true;
12611 }
12612 on_update_channel_full_slow_mode_next_send_date(channel_full, slow_mode_next_send_date);
12613
12614 Channel *c = get_channel(channel_id);
12615 CHECK(c != nullptr);
12616 bool is_slow_mode_enabled = slow_mode_delay != 0;
12617 if (is_slow_mode_enabled != c->is_slow_mode_enabled) {
12618 c->is_slow_mode_enabled = is_slow_mode_enabled;
12619 c->is_changed = true;
12620 update_channel(c, channel_id);
12621 }
12622 }
12623
on_update_channel_full_slow_mode_next_send_date(ChannelFull * channel_full,int32 slow_mode_next_send_date)12624 void ContactsManager::on_update_channel_full_slow_mode_next_send_date(ChannelFull *channel_full,
12625 int32 slow_mode_next_send_date) {
12626 if (slow_mode_next_send_date < 0) {
12627 LOG(ERROR) << "Receive slow mode next send date " << slow_mode_next_send_date;
12628 slow_mode_next_send_date = 0;
12629 }
12630 if (channel_full->slow_mode_delay == 0 && slow_mode_next_send_date > 0) {
12631 LOG(ERROR) << "Slow mode is disabled, but next send date is " << slow_mode_next_send_date;
12632 slow_mode_next_send_date = 0;
12633 }
12634
12635 if (slow_mode_next_send_date != 0) {
12636 auto now = G()->unix_time();
12637 if (slow_mode_next_send_date <= now) {
12638 slow_mode_next_send_date = 0;
12639 }
12640 if (slow_mode_next_send_date > now + 3601) {
12641 slow_mode_next_send_date = now + 3601;
12642 }
12643 }
12644 if (channel_full->slow_mode_next_send_date != slow_mode_next_send_date) {
12645 channel_full->slow_mode_next_send_date = slow_mode_next_send_date;
12646 channel_full->is_slow_mode_next_send_date_changed = true;
12647 channel_full->is_changed = true;
12648 }
12649 }
12650
on_get_dialog_invite_link_info(const string & invite_link,tl_object_ptr<telegram_api::ChatInvite> && chat_invite_ptr,Promise<Unit> && promise)12651 void ContactsManager::on_get_dialog_invite_link_info(const string &invite_link,
12652 tl_object_ptr<telegram_api::ChatInvite> &&chat_invite_ptr,
12653 Promise<Unit> &&promise) {
12654 CHECK(chat_invite_ptr != nullptr);
12655 switch (chat_invite_ptr->get_id()) {
12656 case telegram_api::chatInviteAlready::ID:
12657 case telegram_api::chatInvitePeek::ID: {
12658 telegram_api::object_ptr<telegram_api::Chat> chat = nullptr;
12659 int32 accessible_before = 0;
12660 if (chat_invite_ptr->get_id() == telegram_api::chatInviteAlready::ID) {
12661 auto chat_invite_already = move_tl_object_as<telegram_api::chatInviteAlready>(chat_invite_ptr);
12662 chat = std::move(chat_invite_already->chat_);
12663 } else {
12664 auto chat_invite_peek = move_tl_object_as<telegram_api::chatInvitePeek>(chat_invite_ptr);
12665 chat = std::move(chat_invite_peek->chat_);
12666 accessible_before = chat_invite_peek->expires_;
12667 }
12668 auto chat_id = get_chat_id(chat);
12669 if (chat_id != ChatId() && !chat_id.is_valid()) {
12670 LOG(ERROR) << "Receive invalid " << chat_id;
12671 chat_id = ChatId();
12672 }
12673 auto channel_id = get_channel_id(chat);
12674 if (channel_id != ChannelId() && !channel_id.is_valid()) {
12675 LOG(ERROR) << "Receive invalid " << channel_id;
12676 channel_id = ChannelId();
12677 }
12678 if (!channel_id.is_valid() || accessible_before < 0) {
12679 LOG(ERROR) << "Receive expires = " << accessible_before << " for invite link " << invite_link << " to "
12680 << to_string(chat);
12681 accessible_before = 0;
12682 }
12683 on_get_chat(std::move(chat), "chatInviteAlready");
12684
12685 CHECK(chat_id == ChatId() || channel_id == ChannelId());
12686
12687 // the access is already expired, reget the info
12688 if (accessible_before != 0 && accessible_before <= G()->unix_time() + 1) {
12689 td_->create_handler<CheckChatInviteQuery>(std::move(promise))->send(invite_link);
12690 return;
12691 }
12692
12693 DialogId dialog_id = chat_id.is_valid() ? DialogId(chat_id) : DialogId(channel_id);
12694 auto &invite_link_info = invite_link_infos_[invite_link];
12695 if (invite_link_info == nullptr) {
12696 invite_link_info = make_unique<InviteLinkInfo>();
12697 }
12698 invite_link_info->dialog_id = dialog_id;
12699 if (accessible_before != 0) {
12700 auto &access = dialog_access_by_invite_link_[dialog_id];
12701 access.invite_links.insert(invite_link);
12702 if (access.accessible_before < accessible_before) {
12703 access.accessible_before = accessible_before;
12704
12705 auto expires_in = accessible_before - G()->unix_time() - 1;
12706 invite_link_info_expire_timeout_.set_timeout_in(dialog_id.get(), expires_in);
12707 }
12708 }
12709 break;
12710 }
12711 case telegram_api::chatInvite::ID: {
12712 auto chat_invite = move_tl_object_as<telegram_api::chatInvite>(chat_invite_ptr);
12713 vector<UserId> participant_user_ids;
12714 for (auto &user : chat_invite->participants_) {
12715 auto user_id = get_user_id(user);
12716 if (!user_id.is_valid()) {
12717 LOG(ERROR) << "Receive invalid " << user_id;
12718 continue;
12719 }
12720
12721 on_get_user(std::move(user), "chatInvite");
12722 participant_user_ids.push_back(user_id);
12723 }
12724
12725 auto &invite_link_info = invite_link_infos_[invite_link];
12726 if (invite_link_info == nullptr) {
12727 invite_link_info = make_unique<InviteLinkInfo>();
12728 }
12729 invite_link_info->dialog_id = DialogId();
12730 invite_link_info->title = chat_invite->title_;
12731 invite_link_info->photo = get_photo(td_->file_manager_.get(), std::move(chat_invite->photo_), DialogId());
12732 invite_link_info->description = std::move(chat_invite->about_);
12733 invite_link_info->participant_count = chat_invite->participants_count_;
12734 invite_link_info->participant_user_ids = std::move(participant_user_ids);
12735 invite_link_info->creates_join_request = std::move(chat_invite->request_needed_);
12736 invite_link_info->is_chat = (chat_invite->flags_ & CHAT_INVITE_FLAG_IS_CHANNEL) == 0;
12737 invite_link_info->is_channel = (chat_invite->flags_ & CHAT_INVITE_FLAG_IS_CHANNEL) != 0;
12738
12739 bool is_broadcast = (chat_invite->flags_ & CHAT_INVITE_FLAG_IS_BROADCAST) != 0;
12740 bool is_public = (chat_invite->flags_ & CHAT_INVITE_FLAG_IS_PUBLIC) != 0;
12741 bool is_megagroup = (chat_invite->flags_ & CHAT_INVITE_FLAG_IS_MEGAGROUP) != 0;
12742
12743 if (!invite_link_info->is_channel) {
12744 if (is_broadcast || is_public || is_megagroup) {
12745 LOG(ERROR) << "Receive wrong chat invite: " << to_string(chat_invite);
12746 is_public = is_megagroup = false;
12747 }
12748 } else {
12749 LOG_IF(ERROR, is_broadcast == is_megagroup) << "Receive wrong chat invite: " << to_string(chat_invite);
12750 }
12751
12752 invite_link_info->is_public = is_public;
12753 invite_link_info->is_megagroup = is_megagroup;
12754 break;
12755 }
12756 default:
12757 UNREACHABLE();
12758 }
12759 promise.set_value(Unit());
12760 }
12761
remove_dialog_access_by_invite_link(DialogId dialog_id)12762 void ContactsManager::remove_dialog_access_by_invite_link(DialogId dialog_id) {
12763 auto access_it = dialog_access_by_invite_link_.find(dialog_id);
12764 if (access_it == dialog_access_by_invite_link_.end()) {
12765 return;
12766 }
12767
12768 for (auto &invite_link : access_it->second.invite_links) {
12769 invalidate_invite_link_info(invite_link);
12770 }
12771 dialog_access_by_invite_link_.erase(access_it);
12772
12773 invite_link_info_expire_timeout_.cancel_timeout(dialog_id.get());
12774 }
12775
update_permanent_invite_link(DialogInviteLink & invite_link,DialogInviteLink new_invite_link)12776 bool ContactsManager::update_permanent_invite_link(DialogInviteLink &invite_link, DialogInviteLink new_invite_link) {
12777 if (new_invite_link != invite_link) {
12778 if (invite_link.is_valid() && invite_link.get_invite_link() != new_invite_link.get_invite_link()) {
12779 // old link was invalidated
12780 invite_link_infos_.erase(invite_link.get_invite_link());
12781 }
12782
12783 invite_link = std::move(new_invite_link);
12784 return true;
12785 }
12786 return false;
12787 }
12788
invalidate_invite_link_info(const string & invite_link)12789 void ContactsManager::invalidate_invite_link_info(const string &invite_link) {
12790 LOG(INFO) << "Invalidate info about invite link " << invite_link;
12791 invite_link_infos_.erase(invite_link);
12792 }
12793
repair_chat_participants(ChatId chat_id)12794 void ContactsManager::repair_chat_participants(ChatId chat_id) {
12795 send_get_chat_full_query(chat_id, Auto(), "repair_chat_participants");
12796 }
12797
on_update_chat_add_user(ChatId chat_id,UserId inviter_user_id,UserId user_id,int32 date,int32 version)12798 void ContactsManager::on_update_chat_add_user(ChatId chat_id, UserId inviter_user_id, UserId user_id, int32 date,
12799 int32 version) {
12800 if (!chat_id.is_valid()) {
12801 LOG(ERROR) << "Receive invalid " << chat_id;
12802 return;
12803 }
12804 if (!have_user(user_id)) {
12805 LOG(ERROR) << "Can't find " << user_id;
12806 return;
12807 }
12808 if (!have_user(inviter_user_id)) {
12809 LOG(ERROR) << "Can't find " << inviter_user_id;
12810 return;
12811 }
12812 LOG(INFO) << "Receive updateChatParticipantAdd to " << chat_id << " with " << user_id << " invited by "
12813 << inviter_user_id << " at " << date << " with version " << version;
12814
12815 ChatFull *chat_full = get_chat_full_force(chat_id, "on_update_chat_add_user");
12816 if (chat_full == nullptr) {
12817 LOG(INFO) << "Ignoring update about members of " << chat_id;
12818 return;
12819 }
12820 auto c = get_chat(chat_id);
12821 if (c == nullptr) {
12822 LOG(ERROR) << "Receive updateChatParticipantAdd for unknown " << chat_id << ". Couldn't apply it";
12823 repair_chat_participants(chat_id);
12824 return;
12825 }
12826 if (c->status.is_left()) {
12827 // possible if updates come out of order
12828 LOG(WARNING) << "Receive updateChatParticipantAdd for left " << chat_id << ". Couldn't apply it";
12829
12830 repair_chat_participants(chat_id); // just in case
12831 return;
12832 }
12833 if (on_update_chat_full_participants_short(chat_full, chat_id, version)) {
12834 for (auto &participant : chat_full->participants) {
12835 if (participant.dialog_id_ == DialogId(user_id)) {
12836 if (participant.inviter_user_id_ != inviter_user_id) {
12837 LOG(ERROR) << user_id << " was readded to " << chat_id << " by " << inviter_user_id
12838 << ", previously invited by " << participant.inviter_user_id_;
12839 participant.inviter_user_id_ = inviter_user_id;
12840 participant.joined_date_ = date;
12841 repair_chat_participants(chat_id);
12842 } else {
12843 // Possible if update comes twice
12844 LOG(INFO) << user_id << " was readded to " << chat_id;
12845 }
12846 return;
12847 }
12848 }
12849 chat_full->participants.push_back(DialogParticipant{DialogId(user_id), inviter_user_id, date,
12850 user_id == chat_full->creator_user_id
12851 ? DialogParticipantStatus::Creator(true, false, string())
12852 : DialogParticipantStatus::Member()});
12853 update_chat_online_member_count(chat_full, chat_id, false);
12854 chat_full->is_changed = true;
12855 update_chat_full(chat_full, chat_id, "on_update_chat_add_user");
12856
12857 // Chat is already updated
12858 if (chat_full->version == c->version &&
12859 narrow_cast<int32>(chat_full->participants.size()) != c->participant_count) {
12860 LOG(ERROR) << "Number of members in " << chat_id << " with version " << c->version << " is "
12861 << c->participant_count << " but there are " << chat_full->participants.size()
12862 << " members in the ChatFull";
12863 repair_chat_participants(chat_id);
12864 }
12865 }
12866 }
12867
on_update_chat_edit_administrator(ChatId chat_id,UserId user_id,bool is_administrator,int32 version)12868 void ContactsManager::on_update_chat_edit_administrator(ChatId chat_id, UserId user_id, bool is_administrator,
12869 int32 version) {
12870 if (!chat_id.is_valid()) {
12871 LOG(ERROR) << "Receive invalid " << chat_id;
12872 return;
12873 }
12874 if (!have_user(user_id)) {
12875 LOG(ERROR) << "Can't find " << user_id;
12876 return;
12877 }
12878 LOG(INFO) << "Receive updateChatParticipantAdmin in " << chat_id << " with " << user_id << ", administrator rights "
12879 << (is_administrator ? "enabled" : "disabled") << " with version " << version;
12880
12881 auto c = get_chat_force(chat_id);
12882 if (c == nullptr) {
12883 LOG(INFO) << "Ignoring update about members of unknown " << chat_id;
12884 return;
12885 }
12886
12887 if (c->status.is_left()) {
12888 // possible if updates come out of order
12889 LOG(WARNING) << "Receive updateChatParticipantAdmin for left " << chat_id << ". Couldn't apply it";
12890
12891 repair_chat_participants(chat_id); // just in case
12892 return;
12893 }
12894 if (version <= -1) {
12895 LOG(ERROR) << "Receive wrong version " << version << " for " << chat_id;
12896 return;
12897 }
12898 CHECK(c->version >= 0);
12899
12900 auto status = is_administrator ? DialogParticipantStatus::GroupAdministrator(c->status.is_creator())
12901 : DialogParticipantStatus::Member();
12902 if (version > c->version) {
12903 if (version != c->version + 1) {
12904 LOG(INFO) << "Administrators of " << chat_id << " with version " << c->version
12905 << " has changed, but new version is " << version;
12906 repair_chat_participants(chat_id);
12907 return;
12908 }
12909
12910 c->version = version;
12911 c->need_save_to_database = true;
12912 if (user_id == get_my_id() && !c->status.is_creator()) {
12913 // if chat with version was already received, then the update is already processed
12914 // so we need to call on_update_chat_status only if version > c->version
12915 on_update_chat_status(c, chat_id, status);
12916 }
12917 update_chat(c, chat_id);
12918 }
12919
12920 ChatFull *chat_full = get_chat_full_force(chat_id, "on_update_chat_edit_administrator");
12921 if (chat_full != nullptr) {
12922 if (chat_full->version + 1 == version) {
12923 for (auto &participant : chat_full->participants) {
12924 if (participant.dialog_id_ == DialogId(user_id)) {
12925 participant.status_ = std::move(status);
12926 chat_full->is_changed = true;
12927 update_chat_full(chat_full, chat_id, "on_update_chat_edit_administrator");
12928 return;
12929 }
12930 }
12931 }
12932
12933 // can't find chat member or version have increased too much
12934 repair_chat_participants(chat_id);
12935 }
12936 }
12937
on_update_chat_delete_user(ChatId chat_id,UserId user_id,int32 version)12938 void ContactsManager::on_update_chat_delete_user(ChatId chat_id, UserId user_id, int32 version) {
12939 if (!chat_id.is_valid()) {
12940 LOG(ERROR) << "Receive invalid " << chat_id;
12941 return;
12942 }
12943 if (!have_user(user_id)) {
12944 LOG(ERROR) << "Can't find " << user_id;
12945 return;
12946 }
12947 LOG(INFO) << "Receive updateChatParticipantDelete from " << chat_id << " with " << user_id << " and version "
12948 << version;
12949
12950 ChatFull *chat_full = get_chat_full_force(chat_id, "on_update_chat_delete_user");
12951 if (chat_full == nullptr) {
12952 LOG(INFO) << "Ignoring update about members of " << chat_id;
12953 return;
12954 }
12955 const Chat *c = get_chat_force(chat_id);
12956 if (c == nullptr) {
12957 LOG(ERROR) << "Receive updateChatParticipantDelete for unknown " << chat_id;
12958 repair_chat_participants(chat_id);
12959 return;
12960 }
12961 if (user_id == get_my_id()) {
12962 LOG_IF(WARNING, c->status.is_member()) << "User was removed from " << chat_id
12963 << " but it is not left the group. Possible if updates comes out of order";
12964 return;
12965 }
12966 if (c->status.is_left()) {
12967 // possible if updates come out of order
12968 LOG(INFO) << "Receive updateChatParticipantDelete for left " << chat_id;
12969
12970 repair_chat_participants(chat_id);
12971 return;
12972 }
12973 if (on_update_chat_full_participants_short(chat_full, chat_id, version)) {
12974 for (size_t i = 0; i < chat_full->participants.size(); i++) {
12975 if (chat_full->participants[i].dialog_id_ == DialogId(user_id)) {
12976 chat_full->participants[i] = chat_full->participants.back();
12977 chat_full->participants.resize(chat_full->participants.size() - 1);
12978 chat_full->is_changed = true;
12979 update_chat_online_member_count(chat_full, chat_id, false);
12980 update_chat_full(chat_full, chat_id, "on_update_chat_delete_user");
12981
12982 if (static_cast<int32>(chat_full->participants.size()) != c->participant_count) {
12983 repair_chat_participants(chat_id);
12984 }
12985 return;
12986 }
12987 }
12988 LOG(ERROR) << "Can't find basic group member " << user_id << " in " << chat_id << " to be removed";
12989 repair_chat_participants(chat_id);
12990 }
12991 }
12992
on_update_chat_status(Chat * c,ChatId chat_id,DialogParticipantStatus status)12993 void ContactsManager::on_update_chat_status(Chat *c, ChatId chat_id, DialogParticipantStatus status) {
12994 if (c->status != status) {
12995 LOG(INFO) << "Update " << chat_id << " status from " << c->status << " to " << status;
12996 bool need_reload_group_call = c->status.can_manage_calls() != status.can_manage_calls();
12997 bool need_drop_invite_link = c->status.can_manage_invite_links() && !status.can_manage_invite_links();
12998
12999 c->status = std::move(status);
13000 c->is_status_changed = true;
13001
13002 if (c->status.is_left()) {
13003 c->participant_count = 0;
13004 c->version = -1;
13005 c->default_permissions_version = -1;
13006 c->pinned_message_version = -1;
13007
13008 drop_chat_full(chat_id);
13009 } else if (need_drop_invite_link) {
13010 ChatFull *chat_full = get_chat_full_force(chat_id, "on_update_chat_status");
13011 if (chat_full != nullptr) {
13012 on_update_chat_full_invite_link(chat_full, nullptr);
13013 update_chat_full(chat_full, chat_id, "on_update_chat_status");
13014 }
13015 }
13016 if (need_reload_group_call) {
13017 send_closure_later(G()->messages_manager(), &MessagesManager::on_update_dialog_group_call_rights,
13018 DialogId(chat_id));
13019 }
13020
13021 c->is_changed = true;
13022 }
13023 }
13024
on_update_chat_default_permissions(ChatId chat_id,RestrictedRights default_permissions,int32 version)13025 void ContactsManager::on_update_chat_default_permissions(ChatId chat_id, RestrictedRights default_permissions,
13026 int32 version) {
13027 if (!chat_id.is_valid()) {
13028 LOG(ERROR) << "Receive invalid " << chat_id;
13029 return;
13030 }
13031 auto c = get_chat_force(chat_id);
13032 if (c == nullptr) {
13033 LOG(INFO) << "Ignoring update about unknown " << chat_id;
13034 return;
13035 }
13036
13037 LOG(INFO) << "Receive updateChatDefaultBannedRights in " << chat_id << " with " << default_permissions
13038 << " and version " << version << ". Current version is " << c->version;
13039
13040 if (c->status.is_left()) {
13041 // possible if updates come out of order
13042 LOG(WARNING) << "Receive updateChatDefaultBannedRights for left " << chat_id << ". Couldn't apply it";
13043
13044 repair_chat_participants(chat_id); // just in case
13045 return;
13046 }
13047 if (version <= -1) {
13048 LOG(ERROR) << "Receive wrong version " << version << " for " << chat_id;
13049 return;
13050 }
13051 CHECK(c->version >= 0);
13052
13053 if (version > c->version) {
13054 // this should be unreachable, because version and default permissions must be already updated from
13055 // the chat object in on_chat_update
13056 if (version != c->version + 1) {
13057 LOG(INFO) << "Default permissions of " << chat_id << " with version " << c->version
13058 << " has changed, but new version is " << version;
13059 repair_chat_participants(chat_id);
13060 return;
13061 }
13062
13063 LOG_IF(ERROR, default_permissions == c->default_permissions)
13064 << "Receive updateChatDefaultBannedRights in " << chat_id << " with version " << version
13065 << " and default_permissions = " << default_permissions
13066 << ", but default_permissions are not changed. Current version is " << c->version;
13067 c->version = version;
13068 c->need_save_to_database = true;
13069 on_update_chat_default_permissions(c, chat_id, default_permissions, version);
13070 update_chat(c, chat_id);
13071 }
13072 }
13073
on_update_chat_default_permissions(Chat * c,ChatId chat_id,RestrictedRights default_permissions,int32 version)13074 void ContactsManager::on_update_chat_default_permissions(Chat *c, ChatId chat_id, RestrictedRights default_permissions,
13075 int32 version) {
13076 if (c->default_permissions != default_permissions && version >= c->default_permissions_version) {
13077 LOG(INFO) << "Update " << chat_id << " default permissions from " << c->default_permissions << " to "
13078 << default_permissions << " and version from " << c->default_permissions_version << " to " << version;
13079 c->default_permissions = default_permissions;
13080 c->default_permissions_version = version;
13081 c->is_default_permissions_changed = true;
13082 c->need_save_to_database = true;
13083 }
13084 }
13085
on_update_chat_noforwards(Chat * c,ChatId chat_id,bool noforwards)13086 void ContactsManager::on_update_chat_noforwards(Chat *c, ChatId chat_id, bool noforwards) {
13087 if (c->noforwards != noforwards) {
13088 LOG(INFO) << "Update " << chat_id << " has_protected_content from " << c->noforwards << " to " << noforwards;
13089 c->noforwards = noforwards;
13090 c->is_noforwards_changed = true;
13091 c->need_save_to_database = true;
13092 }
13093 }
13094
on_update_chat_pinned_message(ChatId chat_id,MessageId pinned_message_id,int32 version)13095 void ContactsManager::on_update_chat_pinned_message(ChatId chat_id, MessageId pinned_message_id, int32 version) {
13096 if (!chat_id.is_valid()) {
13097 LOG(ERROR) << "Receive invalid " << chat_id;
13098 return;
13099 }
13100 auto c = get_chat_force(chat_id);
13101 if (c == nullptr) {
13102 LOG(INFO) << "Ignoring update about unknown " << chat_id;
13103 return;
13104 }
13105
13106 LOG(INFO) << "Receive updateChatPinnedMessage in " << chat_id << " with " << pinned_message_id << " and version "
13107 << version << ". Current version is " << c->version << "/" << c->pinned_message_version;
13108
13109 if (c->status.is_left()) {
13110 // possible if updates come out of order
13111 repair_chat_participants(chat_id); // just in case
13112 return;
13113 }
13114 if (version <= -1) {
13115 LOG(ERROR) << "Receive wrong version " << version << " for " << chat_id;
13116 return;
13117 }
13118 CHECK(c->version >= 0);
13119
13120 if (version >= c->pinned_message_version) {
13121 if (version != c->version + 1 && version != c->version) {
13122 LOG(INFO) << "Pinned message of " << chat_id << " with version " << c->version
13123 << " has changed, but new version is " << version;
13124 repair_chat_participants(chat_id);
13125 } else if (version == c->version + 1) {
13126 c->version = version;
13127 c->need_save_to_database = true;
13128 }
13129 td_->messages_manager_->on_update_dialog_last_pinned_message_id(DialogId(chat_id), pinned_message_id);
13130 if (version > c->pinned_message_version) {
13131 LOG(INFO) << "Change pinned message version of " << chat_id << " from " << c->pinned_message_version << " to "
13132 << version;
13133 c->pinned_message_version = version;
13134 c->need_save_to_database = true;
13135 }
13136 update_chat(c, chat_id);
13137 }
13138 }
13139
on_update_chat_participant_count(Chat * c,ChatId chat_id,int32 participant_count,int32 version,const string & debug_str)13140 void ContactsManager::on_update_chat_participant_count(Chat *c, ChatId chat_id, int32 participant_count, int32 version,
13141 const string &debug_str) {
13142 if (version <= -1) {
13143 LOG(ERROR) << "Receive wrong version " << version << " in " << chat_id << debug_str;
13144 return;
13145 }
13146
13147 if (version < c->version) {
13148 // some outdated data
13149 LOG(INFO) << "Receive number of members in " << chat_id << " with version " << version << debug_str
13150 << ", but current version is " << c->version;
13151 return;
13152 }
13153
13154 if (c->participant_count != participant_count) {
13155 if (version == c->version && participant_count != 0) {
13156 // version is not changed when deleted user is removed from the chat
13157 LOG_IF(ERROR, c->participant_count != participant_count + 1)
13158 << "Number of members in " << chat_id << " has changed from " << c->participant_count << " to "
13159 << participant_count << ", but version " << c->version << " remains unchanged" << debug_str;
13160 repair_chat_participants(chat_id);
13161 }
13162
13163 c->participant_count = participant_count;
13164 c->version = version;
13165 c->is_changed = true;
13166 return;
13167 }
13168
13169 if (version > c->version) {
13170 c->version = version;
13171 c->need_save_to_database = true;
13172 }
13173 }
13174
on_update_chat_photo(Chat * c,ChatId chat_id,tl_object_ptr<telegram_api::ChatPhoto> && chat_photo_ptr)13175 void ContactsManager::on_update_chat_photo(Chat *c, ChatId chat_id,
13176 tl_object_ptr<telegram_api::ChatPhoto> &&chat_photo_ptr) {
13177 DialogPhoto new_chat_photo =
13178 get_dialog_photo(td_->file_manager_.get(), DialogId(chat_id), 0, std::move(chat_photo_ptr));
13179 if (td_->auth_manager_->is_bot()) {
13180 new_chat_photo.minithumbnail.clear();
13181 }
13182
13183 if (new_chat_photo != c->photo) {
13184 c->photo = new_chat_photo;
13185 c->is_photo_changed = true;
13186 c->need_save_to_database = true;
13187 }
13188 }
13189
on_update_chat_title(Chat * c,ChatId chat_id,string && title)13190 void ContactsManager::on_update_chat_title(Chat *c, ChatId chat_id, string &&title) {
13191 if (c->title != title) {
13192 c->title = std::move(title);
13193 c->is_title_changed = true;
13194 c->need_save_to_database = true;
13195 }
13196 }
13197
on_update_chat_active(Chat * c,ChatId chat_id,bool is_active)13198 void ContactsManager::on_update_chat_active(Chat *c, ChatId chat_id, bool is_active) {
13199 if (c->is_active != is_active) {
13200 c->is_active = is_active;
13201 c->is_is_active_changed = true;
13202 c->is_changed = true;
13203 }
13204 }
13205
on_update_chat_migrated_to_channel_id(Chat * c,ChatId chat_id,ChannelId migrated_to_channel_id)13206 void ContactsManager::on_update_chat_migrated_to_channel_id(Chat *c, ChatId chat_id, ChannelId migrated_to_channel_id) {
13207 if (c->migrated_to_channel_id != migrated_to_channel_id && migrated_to_channel_id.is_valid()) {
13208 LOG_IF(ERROR, c->migrated_to_channel_id.is_valid())
13209 << "Upgraded supergroup ID for " << chat_id << " has changed from " << c->migrated_to_channel_id << " to "
13210 << migrated_to_channel_id;
13211 c->migrated_to_channel_id = migrated_to_channel_id;
13212 c->is_changed = true;
13213 }
13214 }
13215
on_update_chat_description(ChatId chat_id,string && description)13216 void ContactsManager::on_update_chat_description(ChatId chat_id, string &&description) {
13217 if (!chat_id.is_valid()) {
13218 LOG(ERROR) << "Receive invalid " << chat_id;
13219 return;
13220 }
13221
13222 auto chat_full = get_chat_full_force(chat_id, "on_update_chat_description");
13223 if (chat_full == nullptr) {
13224 return;
13225 }
13226 if (chat_full->description != description) {
13227 chat_full->description = std::move(description);
13228 chat_full->is_changed = true;
13229 update_chat_full(chat_full, chat_id, "on_update_chat_description");
13230 td_->group_call_manager_->on_update_dialog_about(DialogId(chat_id), chat_full->description, true);
13231 }
13232 }
13233
on_update_chat_full_participants_short(ChatFull * chat_full,ChatId chat_id,int32 version)13234 bool ContactsManager::on_update_chat_full_participants_short(ChatFull *chat_full, ChatId chat_id, int32 version) {
13235 if (version <= -1) {
13236 LOG(ERROR) << "Receive wrong version " << version << " for " << chat_id;
13237 return false;
13238 }
13239 if (chat_full->version == -1) {
13240 // chat members are unknown, nothing to update
13241 return false;
13242 }
13243
13244 if (chat_full->version + 1 == version) {
13245 chat_full->version = version;
13246 return true;
13247 }
13248
13249 LOG(INFO) << "Number of members in " << chat_id << " with version " << chat_full->version
13250 << " has changed, but new version is " << version;
13251 repair_chat_participants(chat_id);
13252 return false;
13253 }
13254
on_update_chat_full_participants(ChatFull * chat_full,ChatId chat_id,vector<DialogParticipant> participants,int32 version,bool from_update)13255 void ContactsManager::on_update_chat_full_participants(ChatFull *chat_full, ChatId chat_id,
13256 vector<DialogParticipant> participants, int32 version,
13257 bool from_update) {
13258 if (version <= -1) {
13259 LOG(ERROR) << "Receive members with wrong version " << version << " in " << chat_id;
13260 return;
13261 }
13262
13263 if (version < chat_full->version) {
13264 // some outdated data
13265 LOG(WARNING) << "Receive members of " << chat_id << " with version " << version << " but current version is "
13266 << chat_full->version;
13267 return;
13268 }
13269
13270 if ((chat_full->participants.size() != participants.size() && version == chat_full->version) ||
13271 (from_update && version != chat_full->version + 1)) {
13272 LOG(INFO) << "Members of " << chat_id << " has changed";
13273 // this is possible in very rare situations
13274 repair_chat_participants(chat_id);
13275 }
13276
13277 chat_full->participants = std::move(participants);
13278 chat_full->version = version;
13279 chat_full->is_changed = true;
13280 update_chat_online_member_count(chat_full, chat_id, true);
13281 }
13282
drop_chat_photos(ChatId chat_id,bool is_empty,bool drop_chat_full_photo,const char * source)13283 void ContactsManager::drop_chat_photos(ChatId chat_id, bool is_empty, bool drop_chat_full_photo, const char *source) {
13284 if (drop_chat_full_photo) {
13285 auto chat_full = get_chat_full(chat_id); // must not load ChatFull
13286 if (chat_full == nullptr) {
13287 return;
13288 }
13289
13290 on_update_chat_full_photo(chat_full, chat_id, Photo());
13291 if (!is_empty) {
13292 reload_chat_full(chat_id, Auto());
13293 }
13294 update_chat_full(chat_full, chat_id, "drop_chat_photos");
13295 }
13296 }
13297
drop_chat_full(ChatId chat_id)13298 void ContactsManager::drop_chat_full(ChatId chat_id) {
13299 ChatFull *chat_full = get_chat_full_force(chat_id, "drop_chat_full");
13300 if (chat_full == nullptr) {
13301 drop_chat_photos(chat_id, false, false, "drop_chat_full");
13302 return;
13303 }
13304
13305 LOG(INFO) << "Drop basicGroupFullInfo of " << chat_id;
13306 on_update_chat_full_photo(chat_full, chat_id, Photo());
13307 // chat_full->creator_user_id = UserId();
13308 chat_full->participants.clear();
13309 chat_full->bot_commands.clear();
13310 chat_full->version = -1;
13311 on_update_chat_full_invite_link(chat_full, nullptr);
13312 update_chat_online_member_count(chat_full, chat_id, true);
13313 chat_full->is_changed = true;
13314 update_chat_full(chat_full, chat_id, "drop_chat_full");
13315 }
13316
on_update_channel_photo(Channel * c,ChannelId channel_id,tl_object_ptr<telegram_api::ChatPhoto> && chat_photo_ptr)13317 void ContactsManager::on_update_channel_photo(Channel *c, ChannelId channel_id,
13318 tl_object_ptr<telegram_api::ChatPhoto> &&chat_photo_ptr) {
13319 DialogPhoto new_chat_photo =
13320 get_dialog_photo(td_->file_manager_.get(), DialogId(channel_id), c->access_hash, std::move(chat_photo_ptr));
13321 if (td_->auth_manager_->is_bot()) {
13322 new_chat_photo.minithumbnail.clear();
13323 }
13324
13325 if (new_chat_photo != c->photo) {
13326 c->photo = new_chat_photo;
13327 c->is_photo_changed = true;
13328 c->need_save_to_database = true;
13329 }
13330 }
13331
on_update_channel_title(Channel * c,ChannelId channel_id,string && title)13332 void ContactsManager::on_update_channel_title(Channel *c, ChannelId channel_id, string &&title) {
13333 if (c->title != title) {
13334 c->title = std::move(title);
13335 c->is_title_changed = true;
13336 c->need_save_to_database = true;
13337 }
13338 }
13339
on_update_channel_status(Channel * c,ChannelId channel_id,DialogParticipantStatus && status)13340 void ContactsManager::on_update_channel_status(Channel *c, ChannelId channel_id, DialogParticipantStatus &&status) {
13341 if (c->status != status) {
13342 LOG(INFO) << "Update " << channel_id << " status from " << c->status << " to " << status;
13343 if (c->is_update_supergroup_sent) {
13344 on_channel_status_changed(c, channel_id, c->status, status);
13345 }
13346 c->status = status;
13347 c->is_status_changed = true;
13348 c->is_changed = true;
13349 }
13350 }
13351
on_channel_status_changed(Channel * c,ChannelId channel_id,const DialogParticipantStatus & old_status,const DialogParticipantStatus & new_status)13352 void ContactsManager::on_channel_status_changed(Channel *c, ChannelId channel_id,
13353 const DialogParticipantStatus &old_status,
13354 const DialogParticipantStatus &new_status) {
13355 CHECK(c->is_update_supergroup_sent);
13356 bool have_channel_full = get_channel_full(channel_id) != nullptr;
13357
13358 bool need_reload_group_call = old_status.can_manage_calls() != new_status.can_manage_calls();
13359 if (old_status.can_manage_invite_links() && !new_status.can_manage_invite_links()) {
13360 auto channel_full = get_channel_full(channel_id, true, "on_channel_status_changed");
13361 if (channel_full != nullptr) { // otherwise invite_link will be dropped when the channel is loaded
13362 on_update_channel_full_invite_link(channel_full, nullptr);
13363 do_invalidate_channel_full(channel_full, channel_id, !c->is_slow_mode_enabled);
13364 update_channel_full(channel_full, channel_id, "on_channel_status_changed");
13365 }
13366 } else {
13367 invalidate_channel_full(channel_id, !c->is_slow_mode_enabled);
13368 }
13369
13370 if (old_status.is_creator() != new_status.is_creator()) {
13371 c->is_creator_changed = true;
13372
13373 send_get_channel_full_query(nullptr, channel_id, Auto(), "update channel owner");
13374 reload_dialog_administrators(DialogId(channel_id), 0, Auto());
13375 remove_dialog_suggested_action(SuggestedAction{SuggestedAction::Type::ConvertToGigagroup, DialogId(channel_id)});
13376 }
13377
13378 if (old_status.is_member() != new_status.is_member() || new_status.is_banned()) {
13379 remove_dialog_access_by_invite_link(DialogId(channel_id));
13380
13381 if (new_status.is_member()) {
13382 reload_channel_full(channel_id, Promise<Unit>(), "on_channel_status_changed");
13383 }
13384 }
13385 if (need_reload_group_call) {
13386 send_closure_later(G()->messages_manager(), &MessagesManager::on_update_dialog_group_call_rights,
13387 DialogId(channel_id));
13388 }
13389 if (td_->auth_manager_->is_bot() && old_status.is_administrator() && !new_status.is_administrator()) {
13390 channel_participants_.erase(channel_id);
13391 }
13392 if (td_->auth_manager_->is_bot() && old_status.is_member() && !new_status.is_member() &&
13393 !G()->parameters().use_message_db) {
13394 send_closure_later(G()->messages_manager(), &MessagesManager::on_dialog_deleted, DialogId(channel_id),
13395 Promise<Unit>());
13396 }
13397
13398 // must not load ChannelFull, because must not change the Channel
13399 CHECK(have_channel_full == (get_channel_full(channel_id) != nullptr));
13400 }
13401
on_update_channel_default_permissions(Channel * c,ChannelId channel_id,RestrictedRights default_permissions)13402 void ContactsManager::on_update_channel_default_permissions(Channel *c, ChannelId channel_id,
13403 RestrictedRights default_permissions) {
13404 if (c->default_permissions != default_permissions) {
13405 LOG(INFO) << "Update " << channel_id << " default permissions from " << c->default_permissions << " to "
13406 << default_permissions;
13407 c->default_permissions = default_permissions;
13408 c->is_default_permissions_changed = true;
13409 c->need_save_to_database = true;
13410 }
13411 }
13412
on_update_channel_has_location(Channel * c,ChannelId channel_id,bool has_location)13413 void ContactsManager::on_update_channel_has_location(Channel *c, ChannelId channel_id, bool has_location) {
13414 if (c->has_location != has_location) {
13415 LOG(INFO) << "Update " << channel_id << " has_location from " << c->has_location << " to " << has_location;
13416 c->has_location = has_location;
13417 c->is_has_location_changed = true;
13418 c->is_changed = true;
13419 }
13420 }
13421
on_update_channel_noforwards(Channel * c,ChannelId channel_id,bool noforwards)13422 void ContactsManager::on_update_channel_noforwards(Channel *c, ChannelId channel_id, bool noforwards) {
13423 if (c->noforwards != noforwards) {
13424 LOG(INFO) << "Update " << channel_id << " has_protected_content from " << c->noforwards << " to " << noforwards;
13425 c->noforwards = noforwards;
13426 c->is_noforwards_changed = true;
13427 c->need_save_to_database = true;
13428 }
13429 }
13430
on_update_channel_username(ChannelId channel_id,string && username)13431 void ContactsManager::on_update_channel_username(ChannelId channel_id, string &&username) {
13432 if (!channel_id.is_valid()) {
13433 LOG(ERROR) << "Receive invalid " << channel_id;
13434 return;
13435 }
13436
13437 Channel *c = get_channel_force(channel_id);
13438 if (c != nullptr) {
13439 on_update_channel_username(c, channel_id, std::move(username));
13440 update_channel(c, channel_id);
13441 } else {
13442 LOG(INFO) << "Ignore update channel username about unknown " << channel_id;
13443 }
13444 }
13445
on_update_channel_username(Channel * c,ChannelId channel_id,string && username)13446 void ContactsManager::on_update_channel_username(Channel *c, ChannelId channel_id, string &&username) {
13447 td_->messages_manager_->on_dialog_username_updated(DialogId(channel_id), c->username, username);
13448 if (c->username != username) {
13449 if (c->is_update_supergroup_sent) {
13450 on_channel_username_changed(c, channel_id, c->username, username);
13451 }
13452
13453 c->username = std::move(username);
13454 c->is_username_changed = true;
13455 c->is_changed = true;
13456 }
13457 }
13458
on_channel_username_changed(const Channel * c,ChannelId channel_id,const string & old_username,const string & new_username)13459 void ContactsManager::on_channel_username_changed(const Channel *c, ChannelId channel_id, const string &old_username,
13460 const string &new_username) {
13461 bool have_channel_full = get_channel_full(channel_id) != nullptr;
13462 if (old_username.empty() || new_username.empty()) {
13463 // moving channel from private to public can change availability of chat members
13464 invalidate_channel_full(channel_id, !c->is_slow_mode_enabled);
13465 }
13466
13467 // must not load ChannelFull, because must not change the Channel
13468 CHECK(have_channel_full == (get_channel_full(channel_id) != nullptr));
13469 }
13470
on_update_channel_description(ChannelId channel_id,string && description)13471 void ContactsManager::on_update_channel_description(ChannelId channel_id, string &&description) {
13472 CHECK(channel_id.is_valid());
13473 auto channel_full = get_channel_full_force(channel_id, true, "on_update_channel_description");
13474 if (channel_full == nullptr) {
13475 return;
13476 }
13477 if (channel_full->description != description) {
13478 channel_full->description = std::move(description);
13479 channel_full->is_changed = true;
13480 update_channel_full(channel_full, channel_id, "on_update_channel_description");
13481 td_->group_call_manager_->on_update_dialog_about(DialogId(channel_id), channel_full->description, true);
13482 }
13483 }
13484
on_update_channel_sticker_set(ChannelId channel_id,StickerSetId sticker_set_id)13485 void ContactsManager::on_update_channel_sticker_set(ChannelId channel_id, StickerSetId sticker_set_id) {
13486 CHECK(channel_id.is_valid());
13487 auto channel_full = get_channel_full_force(channel_id, true, "on_update_channel_sticker_set");
13488 if (channel_full == nullptr) {
13489 return;
13490 }
13491 if (channel_full->sticker_set_id != sticker_set_id) {
13492 channel_full->sticker_set_id = sticker_set_id;
13493 channel_full->is_changed = true;
13494 update_channel_full(channel_full, channel_id, "on_update_channel_sticker_set");
13495 }
13496 }
13497
on_update_channel_linked_channel_id(ChannelId channel_id,ChannelId group_channel_id)13498 void ContactsManager::on_update_channel_linked_channel_id(ChannelId channel_id, ChannelId group_channel_id) {
13499 if (channel_id.is_valid()) {
13500 auto channel_full = get_channel_full_force(channel_id, true, "on_update_channel_linked_channel_id 1");
13501 on_update_channel_full_linked_channel_id(channel_full, channel_id, group_channel_id);
13502 if (channel_full != nullptr) {
13503 update_channel_full(channel_full, channel_id, "on_update_channel_linked_channel_id 3");
13504 }
13505 }
13506 if (group_channel_id.is_valid()) {
13507 auto channel_full = get_channel_full_force(group_channel_id, true, "on_update_channel_linked_channel_id 2");
13508 on_update_channel_full_linked_channel_id(channel_full, group_channel_id, channel_id);
13509 if (channel_full != nullptr) {
13510 update_channel_full(channel_full, group_channel_id, "on_update_channel_linked_channel_id 4");
13511 }
13512 }
13513 }
13514
on_update_channel_location(ChannelId channel_id,const DialogLocation & location)13515 void ContactsManager::on_update_channel_location(ChannelId channel_id, const DialogLocation &location) {
13516 auto channel_full = get_channel_full_force(channel_id, true, "on_update_channel_location");
13517 if (channel_full != nullptr) {
13518 on_update_channel_full_location(channel_full, channel_id, location);
13519 update_channel_full(channel_full, channel_id, "on_update_channel_location");
13520 }
13521 }
13522
on_update_channel_slow_mode_delay(ChannelId channel_id,int32 slow_mode_delay,Promise<Unit> && promise)13523 void ContactsManager::on_update_channel_slow_mode_delay(ChannelId channel_id, int32 slow_mode_delay,
13524 Promise<Unit> &&promise) {
13525 TRY_STATUS_PROMISE(promise, G()->close_status());
13526
13527 auto channel_full = get_channel_full_force(channel_id, true, "on_update_channel_slow_mode_delay");
13528 if (channel_full != nullptr) {
13529 on_update_channel_full_slow_mode_delay(channel_full, channel_id, slow_mode_delay, 0);
13530 update_channel_full(channel_full, channel_id, "on_update_channel_slow_mode_delay");
13531 }
13532 promise.set_value(Unit());
13533 }
13534
on_update_channel_slow_mode_next_send_date(ChannelId channel_id,int32 slow_mode_next_send_date)13535 void ContactsManager::on_update_channel_slow_mode_next_send_date(ChannelId channel_id, int32 slow_mode_next_send_date) {
13536 auto channel_full = get_channel_full_force(channel_id, true, "on_update_channel_slow_mode_next_send_date");
13537 if (channel_full != nullptr) {
13538 on_update_channel_full_slow_mode_next_send_date(channel_full, slow_mode_next_send_date);
13539 update_channel_full(channel_full, channel_id, "on_update_channel_slow_mode_next_send_date");
13540 }
13541 }
13542
on_update_channel_bot_user_ids(ChannelId channel_id,vector<UserId> && bot_user_ids)13543 void ContactsManager::on_update_channel_bot_user_ids(ChannelId channel_id, vector<UserId> &&bot_user_ids) {
13544 CHECK(channel_id.is_valid());
13545 if (!have_channel(channel_id)) {
13546 LOG(ERROR) << channel_id << " not found";
13547 return;
13548 }
13549
13550 auto channel_full = get_channel_full_force(channel_id, true, "on_update_channel_bot_user_ids");
13551 if (channel_full == nullptr) {
13552 send_closure_later(G()->messages_manager(), &MessagesManager::on_dialog_bots_updated, DialogId(channel_id),
13553 std::move(bot_user_ids), false);
13554 return;
13555 }
13556 on_update_channel_full_bot_user_ids(channel_full, channel_id, std::move(bot_user_ids));
13557 update_channel_full(channel_full, channel_id, "on_update_channel_bot_user_ids");
13558 }
13559
on_update_channel_full_bot_user_ids(ChannelFull * channel_full,ChannelId channel_id,vector<UserId> && bot_user_ids)13560 void ContactsManager::on_update_channel_full_bot_user_ids(ChannelFull *channel_full, ChannelId channel_id,
13561 vector<UserId> &&bot_user_ids) {
13562 CHECK(channel_full != nullptr);
13563 if (channel_full->bot_user_ids != bot_user_ids) {
13564 send_closure_later(G()->messages_manager(), &MessagesManager::on_dialog_bots_updated, DialogId(channel_id),
13565 bot_user_ids, false);
13566 channel_full->bot_user_ids = std::move(bot_user_ids);
13567 channel_full->need_save_to_database = true;
13568 }
13569 }
13570
on_update_channel_is_all_history_available(ChannelId channel_id,bool is_all_history_available,Promise<Unit> && promise)13571 void ContactsManager::on_update_channel_is_all_history_available(ChannelId channel_id, bool is_all_history_available,
13572 Promise<Unit> &&promise) {
13573 TRY_STATUS_PROMISE(promise, G()->close_status());
13574 CHECK(channel_id.is_valid());
13575 auto channel_full = get_channel_full_force(channel_id, true, "on_update_channel_is_all_history_available");
13576 if (channel_full != nullptr && channel_full->is_all_history_available != is_all_history_available) {
13577 channel_full->is_all_history_available = is_all_history_available;
13578 channel_full->is_changed = true;
13579 update_channel_full(channel_full, channel_id, "on_update_channel_is_all_history_available");
13580 }
13581 promise.set_value(Unit());
13582 }
13583
on_update_channel_default_permissions(ChannelId channel_id,RestrictedRights default_permissions)13584 void ContactsManager::on_update_channel_default_permissions(ChannelId channel_id,
13585 RestrictedRights default_permissions) {
13586 if (!channel_id.is_valid()) {
13587 LOG(ERROR) << "Receive invalid " << channel_id;
13588 return;
13589 }
13590
13591 Channel *c = get_channel_force(channel_id);
13592 if (c != nullptr) {
13593 on_update_channel_default_permissions(c, channel_id, std::move(default_permissions));
13594 update_channel(c, channel_id);
13595 } else {
13596 LOG(INFO) << "Ignore update channel default permissions about unknown " << channel_id;
13597 }
13598 }
13599
send_update_chat_member(DialogId dialog_id,UserId agent_user_id,int32 date,const DialogInviteLink & invite_link,const DialogParticipant & old_dialog_participant,const DialogParticipant & new_dialog_participant)13600 void ContactsManager::send_update_chat_member(DialogId dialog_id, UserId agent_user_id, int32 date,
13601 const DialogInviteLink &invite_link,
13602 const DialogParticipant &old_dialog_participant,
13603 const DialogParticipant &new_dialog_participant) {
13604 CHECK(td_->auth_manager_->is_bot());
13605 td_->messages_manager_->force_create_dialog(dialog_id, "send_update_chat_member", true);
13606 send_closure(G()->td(), &Td::send_update,
13607 td_api::make_object<td_api::updateChatMember>(
13608 dialog_id.get(), get_user_id_object(agent_user_id, "send_update_chat_member"), date,
13609 invite_link.get_chat_invite_link_object(this), get_chat_member_object(old_dialog_participant),
13610 get_chat_member_object(new_dialog_participant)));
13611 }
13612
on_update_bot_stopped(UserId user_id,int32 date,bool is_stopped)13613 void ContactsManager::on_update_bot_stopped(UserId user_id, int32 date, bool is_stopped) {
13614 if (!td_->auth_manager_->is_bot()) {
13615 LOG(ERROR) << "Receive updateBotStopped by non-bot";
13616 return;
13617 }
13618 if (date <= 0 || !have_user_force(user_id)) {
13619 LOG(ERROR) << "Receive invalid updateBotStopped by " << user_id << " at " << date;
13620 return;
13621 }
13622
13623 DialogParticipant old_dialog_participant(DialogId(get_my_id()), user_id, date, DialogParticipantStatus::Banned(0));
13624 DialogParticipant new_dialog_participant(DialogId(get_my_id()), user_id, date, DialogParticipantStatus::Member());
13625 if (is_stopped) {
13626 std::swap(old_dialog_participant.status_, new_dialog_participant.status_);
13627 }
13628
13629 send_update_chat_member(DialogId(user_id), user_id, date, DialogInviteLink(), old_dialog_participant,
13630 new_dialog_participant);
13631 }
13632
on_update_chat_participant(ChatId chat_id,UserId user_id,int32 date,DialogInviteLink invite_link,tl_object_ptr<telegram_api::ChatParticipant> old_participant,tl_object_ptr<telegram_api::ChatParticipant> new_participant)13633 void ContactsManager::on_update_chat_participant(ChatId chat_id, UserId user_id, int32 date,
13634 DialogInviteLink invite_link,
13635 tl_object_ptr<telegram_api::ChatParticipant> old_participant,
13636 tl_object_ptr<telegram_api::ChatParticipant> new_participant) {
13637 if (!td_->auth_manager_->is_bot()) {
13638 LOG(ERROR) << "Receive updateChatParticipant by non-bot";
13639 return;
13640 }
13641 if (!chat_id.is_valid() || !user_id.is_valid() || date <= 0 ||
13642 (old_participant == nullptr && new_participant == nullptr)) {
13643 LOG(ERROR) << "Receive invalid updateChatParticipant in " << chat_id << " by " << user_id << " at " << date << ": "
13644 << to_string(old_participant) << " -> " << to_string(new_participant);
13645 return;
13646 }
13647
13648 const Chat *c = get_chat(chat_id);
13649 if (c == nullptr) {
13650 LOG(ERROR) << "Receive updateChatParticipant in unknown " << chat_id;
13651 return;
13652 }
13653
13654 DialogParticipant old_dialog_participant;
13655 DialogParticipant new_dialog_participant;
13656 if (old_participant != nullptr) {
13657 old_dialog_participant = DialogParticipant(std::move(old_participant), c->date, c->status.is_creator());
13658 if (new_participant == nullptr) {
13659 new_dialog_participant = DialogParticipant::left(old_dialog_participant.dialog_id_);
13660 } else {
13661 new_dialog_participant = DialogParticipant(std::move(new_participant), c->date, c->status.is_creator());
13662 }
13663 } else {
13664 new_dialog_participant = DialogParticipant(std::move(new_participant), c->date, c->status.is_creator());
13665 old_dialog_participant = DialogParticipant::left(new_dialog_participant.dialog_id_);
13666 }
13667 if (old_dialog_participant.dialog_id_ != new_dialog_participant.dialog_id_ || !old_dialog_participant.is_valid() ||
13668 !new_dialog_participant.is_valid()) {
13669 LOG(ERROR) << "Receive wrong updateChatParticipant: " << old_dialog_participant << " -> " << new_dialog_participant;
13670 return;
13671 }
13672 if (new_dialog_participant.dialog_id_ == DialogId(get_my_id()) &&
13673 new_dialog_participant.status_ != get_chat_status(chat_id) && false) {
13674 LOG(ERROR) << "Have status " << get_chat_status(chat_id) << " after receiving updateChatParticipant in " << chat_id
13675 << " by " << user_id << " at " << date << " from " << old_dialog_participant << " to "
13676 << new_dialog_participant;
13677 }
13678
13679 send_update_chat_member(DialogId(chat_id), user_id, date, invite_link, old_dialog_participant,
13680 new_dialog_participant);
13681 }
13682
on_update_channel_participant(ChannelId channel_id,UserId user_id,int32 date,DialogInviteLink invite_link,tl_object_ptr<telegram_api::ChannelParticipant> old_participant,tl_object_ptr<telegram_api::ChannelParticipant> new_participant)13683 void ContactsManager::on_update_channel_participant(ChannelId channel_id, UserId user_id, int32 date,
13684 DialogInviteLink invite_link,
13685 tl_object_ptr<telegram_api::ChannelParticipant> old_participant,
13686 tl_object_ptr<telegram_api::ChannelParticipant> new_participant) {
13687 if (!td_->auth_manager_->is_bot()) {
13688 LOG(ERROR) << "Receive updateChannelParticipant by non-bot";
13689 return;
13690 }
13691 if (!channel_id.is_valid() || !user_id.is_valid() || date <= 0 ||
13692 (old_participant == nullptr && new_participant == nullptr)) {
13693 LOG(ERROR) << "Receive invalid updateChannelParticipant in " << channel_id << " by " << user_id << " at " << date
13694 << ": " << to_string(old_participant) << " -> " << to_string(new_participant);
13695 return;
13696 }
13697
13698 DialogParticipant old_dialog_participant;
13699 DialogParticipant new_dialog_participant;
13700 if (old_participant != nullptr) {
13701 old_dialog_participant = DialogParticipant(std::move(old_participant));
13702 if (new_participant == nullptr) {
13703 new_dialog_participant = DialogParticipant::left(old_dialog_participant.dialog_id_);
13704 } else {
13705 new_dialog_participant = DialogParticipant(std::move(new_participant));
13706 }
13707 } else {
13708 new_dialog_participant = DialogParticipant(std::move(new_participant));
13709 old_dialog_participant = DialogParticipant::left(new_dialog_participant.dialog_id_);
13710 }
13711 if (old_dialog_participant.dialog_id_ != new_dialog_participant.dialog_id_ || !old_dialog_participant.is_valid() ||
13712 !new_dialog_participant.is_valid()) {
13713 LOG(ERROR) << "Receive wrong updateChannelParticipant: " << old_dialog_participant << " -> "
13714 << new_dialog_participant;
13715 return;
13716 }
13717
13718 if (old_dialog_participant.dialog_id_ == DialogId(get_my_id()) && old_dialog_participant.status_.is_administrator() &&
13719 !new_dialog_participant.status_.is_administrator()) {
13720 channel_participants_.erase(channel_id);
13721 } else if (have_channel_participant_cache(channel_id)) {
13722 add_channel_participant_to_cache(channel_id, new_dialog_participant, true);
13723 }
13724 if (new_dialog_participant.dialog_id_ == DialogId(get_my_id()) &&
13725 new_dialog_participant.status_ != get_channel_status(channel_id) && false) {
13726 LOG(ERROR) << "Have status " << get_channel_status(channel_id) << " after receiving updateChannelParticipant in "
13727 << channel_id << " by " << user_id << " at " << date << " from " << old_dialog_participant << " to "
13728 << new_dialog_participant;
13729 }
13730
13731 send_update_chat_member(DialogId(channel_id), user_id, date, invite_link, old_dialog_participant,
13732 new_dialog_participant);
13733 }
13734
on_update_chat_invite_requester(DialogId dialog_id,UserId user_id,string about,int32 date,DialogInviteLink invite_link)13735 void ContactsManager::on_update_chat_invite_requester(DialogId dialog_id, UserId user_id, string about, int32 date,
13736 DialogInviteLink invite_link) {
13737 if (!td_->auth_manager_->is_bot() || date <= 0 || !have_user_force(user_id) ||
13738 !td_->messages_manager_->have_dialog_info_force(dialog_id)) {
13739 LOG(ERROR) << "Receive invalid updateBotChatInviteRequester by " << user_id << " in " << dialog_id << " at "
13740 << date;
13741 return;
13742 }
13743 td_->messages_manager_->force_create_dialog(dialog_id, "on_update_chat_invite_requester", true);
13744
13745 send_closure(G()->td(), &Td::send_update,
13746 td_api::make_object<td_api::updateNewChatJoinRequest>(
13747 dialog_id.get(),
13748 td_api::make_object<td_api::chatJoinRequest>(
13749 get_user_id_object(user_id, "on_update_chat_invite_requester"), date, about),
13750 invite_link.get_chat_invite_link_object(this)));
13751 }
13752
update_contacts_hints(const User * u,UserId user_id,bool from_database)13753 void ContactsManager::update_contacts_hints(const User *u, UserId user_id, bool from_database) {
13754 bool is_contact = is_user_contact(u, user_id, false);
13755 if (td_->auth_manager_->is_bot()) {
13756 LOG_IF(ERROR, is_contact) << "Bot has " << user_id << " in the contacts list";
13757 return;
13758 }
13759
13760 int64 key = user_id.get();
13761 string old_value = contacts_hints_.key_to_string(key);
13762 string new_value = is_contact ? u->first_name + " " + u->last_name + " " + u->username : "";
13763
13764 if (new_value != old_value) {
13765 if (is_contact) {
13766 contacts_hints_.add(key, new_value);
13767 } else {
13768 contacts_hints_.remove(key);
13769 }
13770 }
13771
13772 if (G()->parameters().use_chat_info_db) {
13773 // update contacts database
13774 if (!are_contacts_loaded_) {
13775 if (!from_database && load_contacts_queries_.empty()) {
13776 search_contacts("", std::numeric_limits<int32>::max(), Auto());
13777 }
13778 } else {
13779 if (old_value.empty() == is_contact) {
13780 save_contacts_to_database();
13781 }
13782 }
13783 }
13784 }
13785
have_user(UserId user_id) const13786 bool ContactsManager::have_user(UserId user_id) const {
13787 auto u = get_user(user_id);
13788 return u != nullptr && u->is_received;
13789 }
13790
have_min_user(UserId user_id) const13791 bool ContactsManager::have_min_user(UserId user_id) const {
13792 return users_.count(user_id) > 0;
13793 }
13794
is_user_deleted(UserId user_id) const13795 bool ContactsManager::is_user_deleted(UserId user_id) const {
13796 auto u = get_user(user_id);
13797 return u == nullptr || u->is_deleted;
13798 }
13799
is_user_support(UserId user_id) const13800 bool ContactsManager::is_user_support(UserId user_id) const {
13801 auto u = get_user(user_id);
13802 return u != nullptr && !u->is_deleted && u->is_support;
13803 }
13804
is_user_bot(UserId user_id) const13805 bool ContactsManager::is_user_bot(UserId user_id) const {
13806 auto u = get_user(user_id);
13807 return u != nullptr && !u->is_deleted && u->is_bot;
13808 }
13809
get_bot_data(UserId user_id) const13810 Result<ContactsManager::BotData> ContactsManager::get_bot_data(UserId user_id) const {
13811 auto p = users_.find(user_id);
13812 if (p == users_.end()) {
13813 return Status::Error(400, "Bot not found");
13814 }
13815
13816 auto bot = p->second.get();
13817 if (!bot->is_bot) {
13818 return Status::Error(400, "User is not a bot");
13819 }
13820 if (bot->is_deleted) {
13821 return Status::Error(400, "Bot is deleted");
13822 }
13823 if (!bot->is_received) {
13824 return Status::Error(400, "Bot is inaccessible");
13825 }
13826
13827 BotData bot_data;
13828 bot_data.username = bot->username;
13829 bot_data.can_join_groups = bot->can_join_groups;
13830 bot_data.can_read_all_group_messages = bot->can_read_all_group_messages;
13831 bot_data.is_inline = bot->is_inline_bot;
13832 bot_data.need_location = bot->need_location_bot;
13833 return bot_data;
13834 }
13835
is_user_online(UserId user_id,int32 tolerance) const13836 bool ContactsManager::is_user_online(UserId user_id, int32 tolerance) const {
13837 int32 was_online = get_user_was_online(get_user(user_id), user_id);
13838 return was_online > G()->unix_time() - tolerance;
13839 }
13840
is_user_status_exact(UserId user_id) const13841 bool ContactsManager::is_user_status_exact(UserId user_id) const {
13842 auto u = get_user(user_id);
13843 return u != nullptr && !u->is_deleted && !u->is_bot && u->was_online > 0;
13844 }
13845
can_report_user(UserId user_id) const13846 bool ContactsManager::can_report_user(UserId user_id) const {
13847 auto u = get_user(user_id);
13848 return u != nullptr && !u->is_deleted && !u->is_support && (u->is_bot || all_users_nearby_.count(user_id) != 0);
13849 }
13850
get_user(UserId user_id) const13851 const ContactsManager::User *ContactsManager::get_user(UserId user_id) const {
13852 auto p = users_.find(user_id);
13853 if (p == users_.end()) {
13854 return nullptr;
13855 } else {
13856 return p->second.get();
13857 }
13858 }
13859
get_user(UserId user_id)13860 ContactsManager::User *ContactsManager::get_user(UserId user_id) {
13861 auto p = users_.find(user_id);
13862 if (p == users_.end()) {
13863 return nullptr;
13864 } else {
13865 return p->second.get();
13866 }
13867 }
13868
is_dialog_info_received_from_server(DialogId dialog_id) const13869 bool ContactsManager::is_dialog_info_received_from_server(DialogId dialog_id) const {
13870 switch (dialog_id.get_type()) {
13871 case DialogType::User: {
13872 auto u = get_user(dialog_id.get_user_id());
13873 return u != nullptr && u->is_received_from_server;
13874 }
13875 case DialogType::Chat: {
13876 auto c = get_chat(dialog_id.get_chat_id());
13877 return c != nullptr && c->is_received_from_server;
13878 }
13879 case DialogType::Channel: {
13880 auto c = get_channel(dialog_id.get_channel_id());
13881 return c != nullptr && c->is_received_from_server;
13882 }
13883 default:
13884 return false;
13885 }
13886 }
13887
reload_dialog_info(DialogId dialog_id,Promise<Unit> && promise)13888 void ContactsManager::reload_dialog_info(DialogId dialog_id, Promise<Unit> &&promise) {
13889 switch (dialog_id.get_type()) {
13890 case DialogType::User:
13891 return reload_user(dialog_id.get_user_id(), std::move(promise));
13892 case DialogType::Chat:
13893 return reload_chat(dialog_id.get_chat_id(), std::move(promise));
13894 case DialogType::Channel:
13895 return reload_channel(dialog_id.get_channel_id(), std::move(promise));
13896 default:
13897 return promise.set_error(Status::Error("Invalid dialog ID to reload"));
13898 }
13899 }
13900
send_get_me_query(Td * td,Promise<Unit> && promise)13901 void ContactsManager::send_get_me_query(Td *td, Promise<Unit> &&promise) {
13902 vector<tl_object_ptr<telegram_api::InputUser>> users;
13903 users.push_back(make_tl_object<telegram_api::inputUserSelf>());
13904 td->create_handler<GetUsersQuery>(std::move(promise))->send(std::move(users));
13905 }
13906
get_me(Promise<Unit> && promise)13907 UserId ContactsManager::get_me(Promise<Unit> &&promise) {
13908 auto my_id = get_my_id();
13909 if (!have_user_force(my_id)) {
13910 send_get_me_query(td_, std::move(promise));
13911 return UserId();
13912 }
13913
13914 promise.set_value(Unit());
13915 return my_id;
13916 }
13917
get_user(UserId user_id,int left_tries,Promise<Unit> && promise)13918 bool ContactsManager::get_user(UserId user_id, int left_tries, Promise<Unit> &&promise) {
13919 if (!user_id.is_valid()) {
13920 promise.set_error(Status::Error(400, "Invalid user identifier"));
13921 return false;
13922 }
13923
13924 if (user_id == get_service_notifications_user_id() || user_id == get_replies_bot_user_id() ||
13925 user_id == get_anonymous_bot_user_id()) {
13926 get_user_force(user_id);
13927 }
13928
13929 // TODO support loading user from database and merging it with min-user in memory
13930 if (!have_min_user(user_id)) {
13931 // TODO UserLoader
13932 if (left_tries > 2 && G()->parameters().use_chat_info_db) {
13933 send_closure_later(actor_id(this), &ContactsManager::load_user_from_database, nullptr, user_id,
13934 std::move(promise));
13935 return false;
13936 }
13937 auto input_user = get_input_user(user_id);
13938 if (left_tries == 1 || input_user == nullptr) {
13939 promise.set_error(Status::Error(400, "User not found"));
13940 return false;
13941 }
13942
13943 vector<tl_object_ptr<telegram_api::InputUser>> users;
13944 users.push_back(std::move(input_user));
13945 td_->create_handler<GetUsersQuery>(std::move(promise))->send(std::move(users));
13946 return false;
13947 }
13948
13949 promise.set_value(Unit());
13950 return true;
13951 }
13952
add_user(UserId user_id,const char * source)13953 ContactsManager::User *ContactsManager::add_user(UserId user_id, const char *source) {
13954 CHECK(user_id.is_valid());
13955 auto &user_ptr = users_[user_id];
13956 if (user_ptr == nullptr) {
13957 user_ptr = make_unique<User>();
13958 }
13959 return user_ptr.get();
13960 }
13961
get_user_full(UserId user_id) const13962 const ContactsManager::UserFull *ContactsManager::get_user_full(UserId user_id) const {
13963 auto p = users_full_.find(user_id);
13964 if (p == users_full_.end()) {
13965 return nullptr;
13966 } else {
13967 return p->second.get();
13968 }
13969 }
13970
get_user_full(UserId user_id)13971 ContactsManager::UserFull *ContactsManager::get_user_full(UserId user_id) {
13972 auto p = users_full_.find(user_id);
13973 if (p == users_full_.end()) {
13974 return nullptr;
13975 } else {
13976 return p->second.get();
13977 }
13978 }
13979
add_user_full(UserId user_id)13980 ContactsManager::UserFull *ContactsManager::add_user_full(UserId user_id) {
13981 CHECK(user_id.is_valid());
13982 auto &user_full_ptr = users_full_[user_id];
13983 if (user_full_ptr == nullptr) {
13984 user_full_ptr = make_unique<UserFull>();
13985 }
13986 return user_full_ptr.get();
13987 }
13988
reload_user(UserId user_id,Promise<Unit> && promise)13989 void ContactsManager::reload_user(UserId user_id, Promise<Unit> &&promise) {
13990 if (!user_id.is_valid()) {
13991 return promise.set_error(Status::Error(400, "Invalid user identifier"));
13992 }
13993
13994 have_user_force(user_id);
13995 auto input_user = get_input_user(user_id);
13996 if (input_user == nullptr) {
13997 return promise.set_error(Status::Error(400, "User info not found"));
13998 }
13999
14000 // there is no much reason to combine different requests into one request
14001 vector<tl_object_ptr<telegram_api::InputUser>> users;
14002 users.push_back(std::move(input_user));
14003 td_->create_handler<GetUsersQuery>(std::move(promise))->send(std::move(users));
14004 }
14005
load_user_full(UserId user_id,bool force,Promise<Unit> && promise,const char * source)14006 void ContactsManager::load_user_full(UserId user_id, bool force, Promise<Unit> &&promise, const char *source) {
14007 auto u = get_user(user_id);
14008 if (u == nullptr) {
14009 return promise.set_error(Status::Error(400, "User not found"));
14010 }
14011
14012 auto user_full = get_user_full_force(user_id);
14013 if (user_full == nullptr) {
14014 auto input_user = get_input_user(user_id);
14015 if (input_user == nullptr) {
14016 return promise.set_error(Status::Error(400, "Can't get info about inaccessible user"));
14017 }
14018
14019 return send_get_user_full_query(user_id, std::move(input_user), std::move(promise), source);
14020 }
14021 if (user_full->is_expired()) {
14022 auto input_user = get_input_user(user_id);
14023 CHECK(input_user != nullptr);
14024 if (td_->auth_manager_->is_bot() && !force) {
14025 return send_get_user_full_query(user_id, std::move(input_user), std::move(promise), "load expired user_full");
14026 }
14027
14028 send_get_user_full_query(user_id, std::move(input_user), Auto(), "load expired user_full");
14029 }
14030
14031 promise.set_value(Unit());
14032 }
14033
reload_user_full(UserId user_id)14034 void ContactsManager::reload_user_full(UserId user_id) {
14035 auto input_user = get_input_user(user_id);
14036 if (input_user != nullptr) {
14037 send_get_user_full_query(user_id, std::move(input_user), Auto(), "reload_user_full");
14038 }
14039 }
14040
send_get_user_full_query(UserId user_id,tl_object_ptr<telegram_api::InputUser> && input_user,Promise<Unit> && promise,const char * source)14041 void ContactsManager::send_get_user_full_query(UserId user_id, tl_object_ptr<telegram_api::InputUser> &&input_user,
14042 Promise<Unit> &&promise, const char *source) {
14043 LOG(INFO) << "Get full " << user_id << " from " << source;
14044 auto send_query =
14045 PromiseCreator::lambda([td = td_, input_user = std::move(input_user)](Result<Promise<Unit>> &&promise) mutable {
14046 if (promise.is_ok() && !G()->close_flag()) {
14047 td->create_handler<GetFullUserQuery>(promise.move_as_ok())->send(std::move(input_user));
14048 }
14049 });
14050 get_user_full_queries_.add_query(user_id.get(), std::move(send_query), std::move(promise));
14051 }
14052
get_user_profile_photos(UserId user_id,int32 offset,int32 limit,Promise<Unit> && promise)14053 std::pair<int32, vector<const Photo *>> ContactsManager::get_user_profile_photos(UserId user_id, int32 offset,
14054 int32 limit, Promise<Unit> &&promise) {
14055 std::pair<int32, vector<const Photo *>> result;
14056 result.first = -1;
14057
14058 if (offset < 0) {
14059 promise.set_error(Status::Error(400, "Parameter offset must be non-negative"));
14060 return result;
14061 }
14062 if (limit <= 0) {
14063 promise.set_error(Status::Error(400, "Parameter limit must be positive"));
14064 return result;
14065 }
14066 if (limit > MAX_GET_PROFILE_PHOTOS) {
14067 limit = MAX_GET_PROFILE_PHOTOS;
14068 }
14069
14070 auto input_user = get_input_user(user_id);
14071 if (input_user == nullptr) {
14072 promise.set_error(Status::Error(400, "User not found"));
14073 return result;
14074 }
14075
14076 get_user_dialog_photo(user_id); // apply pending user photo
14077
14078 auto user_photos = &user_photos_[user_id];
14079 if (user_photos->getting_now) {
14080 promise.set_error(Status::Error(400, "Request for new profile photos has already been sent"));
14081 return result;
14082 }
14083
14084 if (user_photos->count != -1) { // know photo count
14085 CHECK(user_photos->offset != -1);
14086 result.first = user_photos->count;
14087
14088 if (offset >= user_photos->count) {
14089 // offset if too big
14090 promise.set_value(Unit());
14091 return result;
14092 }
14093
14094 if (limit > user_photos->count - offset) {
14095 limit = user_photos->count - offset;
14096 }
14097
14098 int32 cache_begin = user_photos->offset;
14099 int32 cache_end = cache_begin + narrow_cast<int32>(user_photos->photos.size());
14100 if (cache_begin <= offset && offset + limit <= cache_end) {
14101 // answer query from cache
14102 for (int i = 0; i < limit; i++) {
14103 result.second.push_back(&user_photos->photos[i + offset - cache_begin]);
14104 }
14105 promise.set_value(Unit());
14106 return result;
14107 }
14108
14109 if (cache_begin <= offset && offset < cache_end) {
14110 // adjust offset to the end of cache
14111 limit = offset + limit - cache_end;
14112 offset = cache_end;
14113 }
14114 }
14115
14116 user_photos->getting_now = true;
14117
14118 if (limit < MAX_GET_PROFILE_PHOTOS / 5) {
14119 limit = MAX_GET_PROFILE_PHOTOS / 5; // make limit reasonable
14120 }
14121
14122 td_->create_handler<GetUserPhotosQuery>(std::move(promise))->send(user_id, std::move(input_user), offset, limit, 0);
14123 return result;
14124 }
14125
reload_user_profile_photo(UserId user_id,int64 photo_id,Promise<Unit> && promise)14126 void ContactsManager::reload_user_profile_photo(UserId user_id, int64 photo_id, Promise<Unit> &&promise) {
14127 get_user_force(user_id);
14128 auto input_user = get_input_user(user_id);
14129 if (input_user == nullptr) {
14130 return promise.set_error(Status::Error(400, "User info not found"));
14131 }
14132
14133 // this request will be needed only to download the photo,
14134 // so there is no reason to combine different requests for a photo into one request
14135 td_->create_handler<GetUserPhotosQuery>(std::move(promise))->send(user_id, std::move(input_user), -1, 1, photo_id);
14136 }
14137
get_user_profile_photo_file_source_id(UserId user_id,int64 photo_id)14138 FileSourceId ContactsManager::get_user_profile_photo_file_source_id(UserId user_id, int64 photo_id) {
14139 auto u = get_user(user_id);
14140 if (u != nullptr && u->photo_ids.count(photo_id) != 0) {
14141 VLOG(file_references) << "Don't need to create file source for photo " << photo_id << " of " << user_id;
14142 // photo was already added, source ID was registered and shouldn't be needed
14143 return FileSourceId();
14144 }
14145
14146 auto &source_id = user_profile_photo_file_source_ids_[std::make_pair(user_id, photo_id)];
14147 if (!source_id.is_valid()) {
14148 source_id = td_->file_reference_manager_->create_user_photo_file_source(user_id, photo_id);
14149 }
14150 VLOG(file_references) << "Return " << source_id << " for photo " << photo_id << " of " << user_id;
14151 return source_id;
14152 }
14153
get_chat_full_file_source_id(ChatId chat_id)14154 FileSourceId ContactsManager::get_chat_full_file_source_id(ChatId chat_id) {
14155 if (get_chat_full(chat_id) != nullptr) {
14156 VLOG(file_references) << "Don't need to create file source for full " << chat_id;
14157 // chat full was already added, source ID was registered and shouldn't be needed
14158 return FileSourceId();
14159 }
14160
14161 auto &source_id = chat_full_file_source_ids_[chat_id];
14162 if (!source_id.is_valid()) {
14163 source_id = td_->file_reference_manager_->create_chat_full_file_source(chat_id);
14164 }
14165 VLOG(file_references) << "Return " << source_id << " for full " << chat_id;
14166 return source_id;
14167 }
14168
get_channel_full_file_source_id(ChannelId channel_id)14169 FileSourceId ContactsManager::get_channel_full_file_source_id(ChannelId channel_id) {
14170 if (get_channel_full(channel_id) != nullptr) {
14171 VLOG(file_references) << "Don't need to create file source for full " << channel_id;
14172 // channel full was already added, source ID was registered and shouldn't be needed
14173 return FileSourceId();
14174 }
14175
14176 auto &source_id = channel_full_file_source_ids_[channel_id];
14177 if (!source_id.is_valid()) {
14178 source_id = td_->file_reference_manager_->create_channel_full_file_source(channel_id);
14179 }
14180 VLOG(file_references) << "Return " << source_id << " for full " << channel_id;
14181 return source_id;
14182 }
14183
have_chat(ChatId chat_id) const14184 bool ContactsManager::have_chat(ChatId chat_id) const {
14185 return chats_.count(chat_id) > 0;
14186 }
14187
get_chat(ChatId chat_id) const14188 const ContactsManager::Chat *ContactsManager::get_chat(ChatId chat_id) const {
14189 auto p = chats_.find(chat_id);
14190 if (p == chats_.end()) {
14191 return nullptr;
14192 } else {
14193 return p->second.get();
14194 }
14195 }
14196
get_chat(ChatId chat_id)14197 ContactsManager::Chat *ContactsManager::get_chat(ChatId chat_id) {
14198 auto p = chats_.find(chat_id);
14199 if (p == chats_.end()) {
14200 return nullptr;
14201 } else {
14202 return p->second.get();
14203 }
14204 }
14205
add_chat(ChatId chat_id)14206 ContactsManager::Chat *ContactsManager::add_chat(ChatId chat_id) {
14207 CHECK(chat_id.is_valid());
14208 auto &chat_ptr = chats_[chat_id];
14209 if (chat_ptr == nullptr) {
14210 chat_ptr = make_unique<Chat>();
14211 }
14212 return chat_ptr.get();
14213 }
14214
get_chat(ChatId chat_id,int left_tries,Promise<Unit> && promise)14215 bool ContactsManager::get_chat(ChatId chat_id, int left_tries, Promise<Unit> &&promise) {
14216 if (!chat_id.is_valid()) {
14217 promise.set_error(Status::Error(400, "Invalid basic group identifier"));
14218 return false;
14219 }
14220
14221 if (!have_chat(chat_id)) {
14222 if (left_tries > 2 && G()->parameters().use_chat_info_db) {
14223 send_closure_later(actor_id(this), &ContactsManager::load_chat_from_database, nullptr, chat_id,
14224 std::move(promise));
14225 return false;
14226 }
14227
14228 if (left_tries > 1) {
14229 td_->create_handler<GetChatsQuery>(std::move(promise))->send(vector<int64>{chat_id.get()});
14230 return false;
14231 }
14232
14233 promise.set_error(Status::Error(400, "Group not found"));
14234 return false;
14235 }
14236
14237 promise.set_value(Unit());
14238 return true;
14239 }
14240
reload_chat(ChatId chat_id,Promise<Unit> && promise)14241 void ContactsManager::reload_chat(ChatId chat_id, Promise<Unit> &&promise) {
14242 if (!chat_id.is_valid()) {
14243 return promise.set_error(Status::Error(400, "Invalid basic group identifier"));
14244 }
14245
14246 // there is no much reason to combine different requests into one request
14247 td_->create_handler<GetChatsQuery>(std::move(promise))->send(vector<int64>{chat_id.get()});
14248 }
14249
get_chat_full(ChatId chat_id) const14250 const ContactsManager::ChatFull *ContactsManager::get_chat_full(ChatId chat_id) const {
14251 auto p = chats_full_.find(chat_id);
14252 if (p == chats_full_.end()) {
14253 return nullptr;
14254 } else {
14255 return p->second.get();
14256 }
14257 }
14258
get_chat_full(ChatId chat_id)14259 ContactsManager::ChatFull *ContactsManager::get_chat_full(ChatId chat_id) {
14260 auto p = chats_full_.find(chat_id);
14261 if (p == chats_full_.end()) {
14262 return nullptr;
14263 } else {
14264 return p->second.get();
14265 }
14266 }
14267
add_chat_full(ChatId chat_id)14268 ContactsManager::ChatFull *ContactsManager::add_chat_full(ChatId chat_id) {
14269 CHECK(chat_id.is_valid());
14270 auto &chat_full_ptr = chats_full_[chat_id];
14271 if (chat_full_ptr == nullptr) {
14272 chat_full_ptr = make_unique<ChatFull>();
14273 }
14274 return chat_full_ptr.get();
14275 }
14276
is_chat_full_outdated(const ChatFull * chat_full,const Chat * c,ChatId chat_id)14277 bool ContactsManager::is_chat_full_outdated(const ChatFull *chat_full, const Chat *c, ChatId chat_id) {
14278 CHECK(c != nullptr);
14279 CHECK(chat_full != nullptr);
14280 if (!c->is_active && chat_full->version == -1) {
14281 return false;
14282 }
14283
14284 if (chat_full->version != c->version) {
14285 LOG(INFO) << "Have outdated ChatFull " << chat_id << " with current version " << chat_full->version
14286 << " and chat version " << c->version;
14287 return true;
14288 }
14289
14290 if (c->is_active && c->status.can_manage_invite_links() && !chat_full->invite_link.is_valid()) {
14291 LOG(INFO) << "Have outdated invite link in " << chat_id;
14292 return true;
14293 }
14294
14295 LOG(DEBUG) << "Full " << chat_id << " is up-to-date with version " << chat_full->version;
14296 return false;
14297 }
14298
load_chat_full(ChatId chat_id,bool force,Promise<Unit> && promise,const char * source)14299 void ContactsManager::load_chat_full(ChatId chat_id, bool force, Promise<Unit> &&promise, const char *source) {
14300 auto c = get_chat(chat_id);
14301 if (c == nullptr) {
14302 return promise.set_error(Status::Error(400, "Group not found"));
14303 }
14304
14305 auto chat_full = get_chat_full_force(chat_id, source);
14306 if (chat_full == nullptr) {
14307 LOG(INFO) << "Full " << chat_id << " not found";
14308 return send_get_chat_full_query(chat_id, std::move(promise), source);
14309 }
14310
14311 if (is_chat_full_outdated(chat_full, c, chat_id)) {
14312 LOG(INFO) << "Have outdated full " << chat_id;
14313 if (td_->auth_manager_->is_bot() && !force) {
14314 return send_get_chat_full_query(chat_id, std::move(promise), source);
14315 }
14316
14317 send_get_chat_full_query(chat_id, Auto(), source);
14318 }
14319
14320 promise.set_value(Unit());
14321 }
14322
reload_chat_full(ChatId chat_id,Promise<Unit> && promise)14323 void ContactsManager::reload_chat_full(ChatId chat_id, Promise<Unit> &&promise) {
14324 send_get_chat_full_query(chat_id, std::move(promise), "reload_chat_full");
14325 }
14326
send_get_chat_full_query(ChatId chat_id,Promise<Unit> && promise,const char * source)14327 void ContactsManager::send_get_chat_full_query(ChatId chat_id, Promise<Unit> &&promise, const char *source) {
14328 LOG(INFO) << "Get full " << chat_id << " from " << source;
14329 auto send_query = PromiseCreator::lambda([td = td_, chat_id](Result<Promise<Unit>> &&promise) {
14330 if (promise.is_ok() && !G()->close_flag()) {
14331 td->create_handler<GetFullChatQuery>(promise.move_as_ok())->send(chat_id);
14332 }
14333 });
14334
14335 get_chat_full_queries_.add_query(DialogId(chat_id).get(), std::move(send_query), std::move(promise));
14336 }
14337
get_chat_participant_count(ChatId chat_id) const14338 int32 ContactsManager::get_chat_participant_count(ChatId chat_id) const {
14339 auto c = get_chat(chat_id);
14340 if (c == nullptr) {
14341 return 0;
14342 }
14343 return c->participant_count;
14344 }
14345
get_chat_is_active(ChatId chat_id) const14346 bool ContactsManager::get_chat_is_active(ChatId chat_id) const {
14347 auto c = get_chat(chat_id);
14348 if (c == nullptr) {
14349 return false;
14350 }
14351 return c->is_active;
14352 }
14353
get_chat_migrated_to_channel_id(ChatId chat_id) const14354 ChannelId ContactsManager::get_chat_migrated_to_channel_id(ChatId chat_id) const {
14355 auto c = get_chat(chat_id);
14356 if (c == nullptr) {
14357 return ChannelId();
14358 }
14359 return c->migrated_to_channel_id;
14360 }
14361
get_chat_status(ChatId chat_id) const14362 DialogParticipantStatus ContactsManager::get_chat_status(ChatId chat_id) const {
14363 auto c = get_chat(chat_id);
14364 if (c == nullptr) {
14365 return DialogParticipantStatus::Banned(0);
14366 }
14367 return get_chat_status(c);
14368 }
14369
get_chat_status(const Chat * c)14370 DialogParticipantStatus ContactsManager::get_chat_status(const Chat *c) {
14371 if (!c->is_active) {
14372 return DialogParticipantStatus::Banned(0);
14373 }
14374 return c->status;
14375 }
14376
get_chat_permissions(ChatId chat_id) const14377 DialogParticipantStatus ContactsManager::get_chat_permissions(ChatId chat_id) const {
14378 auto c = get_chat(chat_id);
14379 if (c == nullptr) {
14380 return DialogParticipantStatus::Banned(0);
14381 }
14382 return get_chat_permissions(c);
14383 }
14384
get_chat_permissions(const Chat * c) const14385 DialogParticipantStatus ContactsManager::get_chat_permissions(const Chat *c) const {
14386 if (!c->is_active) {
14387 return DialogParticipantStatus::Banned(0);
14388 }
14389 return c->status.apply_restrictions(c->default_permissions, td_->auth_manager_->is_bot());
14390 }
14391
is_appointed_chat_administrator(ChatId chat_id) const14392 bool ContactsManager::is_appointed_chat_administrator(ChatId chat_id) const {
14393 auto c = get_chat(chat_id);
14394 if (c == nullptr) {
14395 return false;
14396 }
14397 return c->status.is_administrator();
14398 }
14399
is_channel_public(ChannelId channel_id) const14400 bool ContactsManager::is_channel_public(ChannelId channel_id) const {
14401 return is_channel_public(get_channel(channel_id));
14402 }
14403
is_channel_public(const Channel * c)14404 bool ContactsManager::is_channel_public(const Channel *c) {
14405 return c != nullptr && (!c->username.empty() || c->has_location);
14406 }
14407
get_channel_type(ChannelId channel_id) const14408 ContactsManager::ChannelType ContactsManager::get_channel_type(ChannelId channel_id) const {
14409 auto c = get_channel(channel_id);
14410 if (c == nullptr) {
14411 return ChannelType::Unknown;
14412 }
14413 return get_channel_type(c);
14414 }
14415
get_channel_type(const Channel * c)14416 ContactsManager::ChannelType ContactsManager::get_channel_type(const Channel *c) {
14417 if (c->is_megagroup) {
14418 return ChannelType::Megagroup;
14419 }
14420 return ChannelType::Broadcast;
14421 }
14422
get_channel_date(ChannelId channel_id) const14423 int32 ContactsManager::get_channel_date(ChannelId channel_id) const {
14424 auto c = get_channel(channel_id);
14425 if (c == nullptr) {
14426 return 0;
14427 }
14428 return c->date;
14429 }
14430
get_channel_status(ChannelId channel_id) const14431 DialogParticipantStatus ContactsManager::get_channel_status(ChannelId channel_id) const {
14432 auto c = get_channel(channel_id);
14433 if (c == nullptr) {
14434 return DialogParticipantStatus::Banned(0);
14435 }
14436 return get_channel_status(c);
14437 }
14438
get_channel_status(const Channel * c)14439 DialogParticipantStatus ContactsManager::get_channel_status(const Channel *c) {
14440 c->status.update_restrictions();
14441 return c->status;
14442 }
14443
get_channel_permissions(ChannelId channel_id) const14444 DialogParticipantStatus ContactsManager::get_channel_permissions(ChannelId channel_id) const {
14445 auto c = get_channel(channel_id);
14446 if (c == nullptr) {
14447 return DialogParticipantStatus::Banned(0);
14448 }
14449 return get_channel_permissions(c);
14450 }
14451
get_channel_permissions(const Channel * c) const14452 DialogParticipantStatus ContactsManager::get_channel_permissions(const Channel *c) const {
14453 c->status.update_restrictions();
14454 if (!c->is_megagroup) {
14455 // there is no restrictions in broadcast channels
14456 return c->status;
14457 }
14458 return c->status.apply_restrictions(c->default_permissions, td_->auth_manager_->is_bot());
14459 }
14460
get_channel_participant_count(ChannelId channel_id) const14461 int32 ContactsManager::get_channel_participant_count(ChannelId channel_id) const {
14462 auto c = get_channel(channel_id);
14463 if (c == nullptr) {
14464 return 0;
14465 }
14466 return c->participant_count;
14467 }
14468
get_channel_sign_messages(ChannelId channel_id) const14469 bool ContactsManager::get_channel_sign_messages(ChannelId channel_id) const {
14470 auto c = get_channel(channel_id);
14471 if (c == nullptr) {
14472 return false;
14473 }
14474 return get_channel_sign_messages(c);
14475 }
14476
get_channel_sign_messages(const Channel * c)14477 bool ContactsManager::get_channel_sign_messages(const Channel *c) {
14478 return c->sign_messages;
14479 }
14480
get_channel_has_linked_channel(ChannelId channel_id) const14481 bool ContactsManager::get_channel_has_linked_channel(ChannelId channel_id) const {
14482 auto c = get_channel(channel_id);
14483 if (c == nullptr) {
14484 return false;
14485 }
14486 return get_channel_has_linked_channel(c);
14487 }
14488
get_channel_has_linked_channel(const Channel * c)14489 bool ContactsManager::get_channel_has_linked_channel(const Channel *c) {
14490 return c->has_linked_channel;
14491 }
14492
get_channel_linked_channel_id(ChannelId channel_id)14493 ChannelId ContactsManager::get_channel_linked_channel_id(ChannelId channel_id) {
14494 auto channel_full = get_channel_full_const(channel_id);
14495 if (channel_full == nullptr) {
14496 channel_full = get_channel_full_force(channel_id, false, "get_channel_linked_channel_id");
14497 if (channel_full == nullptr) {
14498 return ChannelId();
14499 }
14500 }
14501 return channel_full->linked_channel_id;
14502 }
14503
get_channel_slow_mode_delay(ChannelId channel_id)14504 int32 ContactsManager::get_channel_slow_mode_delay(ChannelId channel_id) {
14505 auto channel_full = get_channel_full_const(channel_id);
14506 if (channel_full == nullptr) {
14507 channel_full = get_channel_full_force(channel_id, false, "get_channel_slow_mode_delay");
14508 if (channel_full == nullptr) {
14509 return 0;
14510 }
14511 }
14512 return channel_full->slow_mode_delay;
14513 }
14514
have_channel(ChannelId channel_id) const14515 bool ContactsManager::have_channel(ChannelId channel_id) const {
14516 return channels_.count(channel_id) > 0;
14517 }
14518
have_min_channel(ChannelId channel_id) const14519 bool ContactsManager::have_min_channel(ChannelId channel_id) const {
14520 return min_channels_.count(channel_id) > 0;
14521 }
14522
get_channel(ChannelId channel_id) const14523 const ContactsManager::Channel *ContactsManager::get_channel(ChannelId channel_id) const {
14524 auto p = channels_.find(channel_id);
14525 if (p == channels_.end()) {
14526 return nullptr;
14527 } else {
14528 return p->second.get();
14529 }
14530 }
14531
get_channel(ChannelId channel_id)14532 ContactsManager::Channel *ContactsManager::get_channel(ChannelId channel_id) {
14533 auto p = channels_.find(channel_id);
14534 if (p == channels_.end()) {
14535 return nullptr;
14536 } else {
14537 return p->second.get();
14538 }
14539 }
14540
add_channel(ChannelId channel_id,const char * source)14541 ContactsManager::Channel *ContactsManager::add_channel(ChannelId channel_id, const char *source) {
14542 CHECK(channel_id.is_valid());
14543 auto &channel_ptr = channels_[channel_id];
14544 if (channel_ptr == nullptr) {
14545 channel_ptr = make_unique<Channel>();
14546 }
14547 return channel_ptr.get();
14548 }
14549
get_channel(ChannelId channel_id,int left_tries,Promise<Unit> && promise)14550 bool ContactsManager::get_channel(ChannelId channel_id, int left_tries, Promise<Unit> &&promise) {
14551 if (!channel_id.is_valid()) {
14552 promise.set_error(Status::Error(400, "Invalid supergroup identifier"));
14553 return false;
14554 }
14555
14556 if (!have_channel(channel_id)) {
14557 if (left_tries > 2 && G()->parameters().use_chat_info_db) {
14558 send_closure_later(actor_id(this), &ContactsManager::load_channel_from_database, nullptr, channel_id,
14559 std::move(promise));
14560 return false;
14561 }
14562
14563 if (left_tries > 1 && td_->auth_manager_->is_bot()) {
14564 td_->create_handler<GetChannelsQuery>(std::move(promise))->send(get_input_channel(channel_id));
14565 return false;
14566 }
14567
14568 promise.set_error(Status::Error(400, "Supergroup not found"));
14569 return false;
14570 }
14571
14572 promise.set_value(Unit());
14573 return true;
14574 }
14575
reload_channel(ChannelId channel_id,Promise<Unit> && promise)14576 void ContactsManager::reload_channel(ChannelId channel_id, Promise<Unit> &&promise) {
14577 if (!channel_id.is_valid()) {
14578 return promise.set_error(Status::Error(400, "Invalid supergroup identifier"));
14579 }
14580
14581 have_channel_force(channel_id);
14582 auto input_channel = get_input_channel(channel_id);
14583 if (input_channel == nullptr) {
14584 input_channel = make_tl_object<telegram_api::inputChannel>(channel_id.get(), 0);
14585 }
14586
14587 // there is no much reason to combine different requests into one request
14588 // requests with 0 access_hash must not be merged
14589 td_->create_handler<GetChannelsQuery>(std::move(promise))->send(std::move(input_channel));
14590 }
14591
get_channel_full_const(ChannelId channel_id) const14592 const ContactsManager::ChannelFull *ContactsManager::get_channel_full_const(ChannelId channel_id) const {
14593 auto p = channels_full_.find(channel_id);
14594 if (p == channels_full_.end()) {
14595 return nullptr;
14596 } else {
14597 return p->second.get();
14598 }
14599 }
14600
get_channel_full(ChannelId channel_id) const14601 const ContactsManager::ChannelFull *ContactsManager::get_channel_full(ChannelId channel_id) const {
14602 return get_channel_full_const(channel_id);
14603 }
14604
get_channel_full(ChannelId channel_id,bool only_local,const char * source)14605 ContactsManager::ChannelFull *ContactsManager::get_channel_full(ChannelId channel_id, bool only_local,
14606 const char *source) {
14607 auto p = channels_full_.find(channel_id);
14608 if (p == channels_full_.end()) {
14609 return nullptr;
14610 }
14611
14612 auto channel_full = p->second.get();
14613 if (!only_local && channel_full->is_expired() && !td_->auth_manager_->is_bot()) {
14614 send_get_channel_full_query(channel_full, channel_id, Auto(), source);
14615 }
14616
14617 return channel_full;
14618 }
14619
add_channel_full(ChannelId channel_id)14620 ContactsManager::ChannelFull *ContactsManager::add_channel_full(ChannelId channel_id) {
14621 CHECK(channel_id.is_valid());
14622 auto &channel_full_ptr = channels_full_[channel_id];
14623 if (channel_full_ptr == nullptr) {
14624 channel_full_ptr = make_unique<ChannelFull>();
14625 }
14626 return channel_full_ptr.get();
14627 }
14628
load_channel_full(ChannelId channel_id,bool force,Promise<Unit> && promise,const char * source)14629 void ContactsManager::load_channel_full(ChannelId channel_id, bool force, Promise<Unit> &&promise, const char *source) {
14630 auto channel_full = get_channel_full_force(channel_id, true, source);
14631 if (channel_full == nullptr) {
14632 return send_get_channel_full_query(channel_full, channel_id, std::move(promise), source);
14633 }
14634 if (channel_full->is_expired()) {
14635 if (td_->auth_manager_->is_bot() && !force) {
14636 return send_get_channel_full_query(channel_full, channel_id, std::move(promise), "load expired channel_full");
14637 }
14638
14639 send_get_channel_full_query(channel_full, channel_id, Auto(), "load expired channel_full");
14640 }
14641
14642 promise.set_value(Unit());
14643 }
14644
reload_channel_full(ChannelId channel_id,Promise<Unit> && promise,const char * source)14645 void ContactsManager::reload_channel_full(ChannelId channel_id, Promise<Unit> &&promise, const char *source) {
14646 send_get_channel_full_query(get_channel_full(channel_id, true, "reload_channel_full"), channel_id, std::move(promise),
14647 source);
14648 }
14649
send_get_channel_full_query(ChannelFull * channel_full,ChannelId channel_id,Promise<Unit> && promise,const char * source)14650 void ContactsManager::send_get_channel_full_query(ChannelFull *channel_full, ChannelId channel_id,
14651 Promise<Unit> &&promise, const char *source) {
14652 auto input_channel = get_input_channel(channel_id);
14653 if (input_channel == nullptr) {
14654 return promise.set_error(Status::Error(400, "Supergroup not found"));
14655 }
14656
14657 if (!have_input_peer_channel(channel_id, AccessRights::Read)) {
14658 return promise.set_error(Status::Error(400, "Can't access the chat"));
14659 }
14660
14661 if (channel_full != nullptr) {
14662 if (!promise) {
14663 if (channel_full->repair_request_version != 0) {
14664 LOG(INFO) << "Skip get full " << channel_id << " request from " << source;
14665 return;
14666 }
14667 channel_full->repair_request_version = channel_full->speculative_version;
14668 } else {
14669 channel_full->repair_request_version = std::numeric_limits<uint32>::max();
14670 }
14671 }
14672
14673 LOG(INFO) << "Get full " << channel_id << " from " << source;
14674 auto send_query = PromiseCreator::lambda(
14675 [td = td_, channel_id, input_channel = std::move(input_channel)](Result<Promise<Unit>> &&promise) mutable {
14676 if (promise.is_ok() && !G()->close_flag()) {
14677 td->create_handler<GetFullChannelQuery>(promise.move_as_ok())->send(channel_id, std::move(input_channel));
14678 }
14679 });
14680 get_chat_full_queries_.add_query(DialogId(channel_id).get(), std::move(send_query), std::move(promise));
14681 }
14682
have_secret_chat(SecretChatId secret_chat_id) const14683 bool ContactsManager::have_secret_chat(SecretChatId secret_chat_id) const {
14684 return secret_chats_.count(secret_chat_id) > 0;
14685 }
14686
add_secret_chat(SecretChatId secret_chat_id)14687 ContactsManager::SecretChat *ContactsManager::add_secret_chat(SecretChatId secret_chat_id) {
14688 CHECK(secret_chat_id.is_valid());
14689 auto &secret_chat_ptr = secret_chats_[secret_chat_id];
14690 if (secret_chat_ptr == nullptr) {
14691 secret_chat_ptr = make_unique<SecretChat>();
14692 }
14693 return secret_chat_ptr.get();
14694 }
14695
get_secret_chat(SecretChatId secret_chat_id) const14696 const ContactsManager::SecretChat *ContactsManager::get_secret_chat(SecretChatId secret_chat_id) const {
14697 auto it = secret_chats_.find(secret_chat_id);
14698 if (it == secret_chats_.end()) {
14699 return nullptr;
14700 }
14701 return it->second.get();
14702 }
14703
get_secret_chat(SecretChatId secret_chat_id)14704 ContactsManager::SecretChat *ContactsManager::get_secret_chat(SecretChatId secret_chat_id) {
14705 auto it = secret_chats_.find(secret_chat_id);
14706 if (it == secret_chats_.end()) {
14707 return nullptr;
14708 }
14709 return it->second.get();
14710 }
14711
get_secret_chat(SecretChatId secret_chat_id,bool force,Promise<Unit> && promise)14712 bool ContactsManager::get_secret_chat(SecretChatId secret_chat_id, bool force, Promise<Unit> &&promise) {
14713 if (!secret_chat_id.is_valid()) {
14714 promise.set_error(Status::Error(400, "Invalid secret chat identifier"));
14715 return false;
14716 }
14717
14718 if (!have_secret_chat(secret_chat_id)) {
14719 if (!force && G()->parameters().use_chat_info_db) {
14720 send_closure_later(actor_id(this), &ContactsManager::load_secret_chat_from_database, nullptr, secret_chat_id,
14721 std::move(promise));
14722 return false;
14723 }
14724
14725 promise.set_error(Status::Error(400, "Secret chat not found"));
14726 return false;
14727 }
14728
14729 promise.set_value(Unit());
14730 return true;
14731 }
14732
on_update_secret_chat(SecretChatId secret_chat_id,int64 access_hash,UserId user_id,SecretChatState state,bool is_outbound,int32 ttl,int32 date,string key_hash,int32 layer,FolderId initial_folder_id)14733 void ContactsManager::on_update_secret_chat(SecretChatId secret_chat_id, int64 access_hash, UserId user_id,
14734 SecretChatState state, bool is_outbound, int32 ttl, int32 date,
14735 string key_hash, int32 layer, FolderId initial_folder_id) {
14736 LOG(INFO) << "Update " << secret_chat_id << " with " << user_id << " and access_hash " << access_hash;
14737 auto *secret_chat = add_secret_chat(secret_chat_id);
14738 if (access_hash != secret_chat->access_hash) {
14739 secret_chat->access_hash = access_hash;
14740 secret_chat->need_save_to_database = true;
14741 }
14742 if (user_id.is_valid() && user_id != secret_chat->user_id) {
14743 if (secret_chat->user_id.is_valid()) {
14744 LOG(ERROR) << "Secret chat user has changed from " << secret_chat->user_id << " to " << user_id;
14745 auto &old_secret_chat_ids = secret_chats_with_user_[secret_chat->user_id];
14746 td::remove(old_secret_chat_ids, secret_chat_id);
14747 }
14748 secret_chat->user_id = user_id;
14749 secret_chats_with_user_[secret_chat->user_id].push_back(secret_chat_id);
14750 secret_chat->is_changed = true;
14751 }
14752 if (state != SecretChatState::Unknown && state != secret_chat->state) {
14753 secret_chat->state = state;
14754 secret_chat->is_changed = true;
14755 secret_chat->is_state_changed = true;
14756 }
14757 if (is_outbound != secret_chat->is_outbound) {
14758 secret_chat->is_outbound = is_outbound;
14759 secret_chat->is_changed = true;
14760 }
14761
14762 if (ttl != -1 && ttl != secret_chat->ttl) {
14763 secret_chat->ttl = ttl;
14764 secret_chat->need_save_to_database = true;
14765 secret_chat->is_ttl_changed = true;
14766 }
14767 if (date != 0 && date != secret_chat->date) {
14768 secret_chat->date = date;
14769 secret_chat->need_save_to_database = true;
14770 }
14771 if (!key_hash.empty() && key_hash != secret_chat->key_hash) {
14772 secret_chat->key_hash = std::move(key_hash);
14773 secret_chat->is_changed = true;
14774 }
14775 if (layer != 0 && layer != secret_chat->layer) {
14776 secret_chat->layer = layer;
14777 secret_chat->is_changed = true;
14778 }
14779 if (initial_folder_id != FolderId() && initial_folder_id != secret_chat->initial_folder_id) {
14780 secret_chat->initial_folder_id = initial_folder_id;
14781 secret_chat->is_changed = true;
14782 }
14783
14784 update_secret_chat(secret_chat, secret_chat_id);
14785 }
14786
search_among_dialogs(const vector<DialogId> & dialog_ids,const string & query,int32 limit) const14787 std::pair<int32, vector<DialogId>> ContactsManager::search_among_dialogs(const vector<DialogId> &dialog_ids,
14788 const string &query, int32 limit) const {
14789 Hints hints; // TODO cache Hints
14790
14791 for (auto dialog_id : dialog_ids) {
14792 int64 rating = 0;
14793 if (dialog_id.get_type() == DialogType::User) {
14794 auto user_id = dialog_id.get_user_id();
14795 auto u = get_user(user_id);
14796 if (u == nullptr) {
14797 continue;
14798 }
14799 if (query.empty()) {
14800 hints.add(dialog_id.get(), Slice(" "));
14801 } else {
14802 hints.add(dialog_id.get(), PSLICE() << u->first_name << ' ' << u->last_name << ' ' << u->username);
14803 }
14804 rating = -get_user_was_online(u, user_id);
14805 } else {
14806 if (!td_->messages_manager_->have_dialog_info(dialog_id)) {
14807 continue;
14808 }
14809 if (query.empty()) {
14810 hints.add(dialog_id.get(), Slice(" "));
14811 } else {
14812 hints.add(dialog_id.get(), td_->messages_manager_->get_dialog_title(dialog_id));
14813 }
14814 }
14815 hints.set_rating(dialog_id.get(), rating);
14816 }
14817
14818 auto result = hints.search(query, limit, true);
14819 return {narrow_cast<int32>(result.first), transform(result.second, [](int64 key) { return DialogId(key); })};
14820 }
14821
add_dialog_participant(DialogId dialog_id,UserId user_id,int32 forward_limit,Promise<Unit> && promise)14822 void ContactsManager::add_dialog_participant(DialogId dialog_id, UserId user_id, int32 forward_limit,
14823 Promise<Unit> &&promise) {
14824 if (!td_->messages_manager_->have_dialog_force(dialog_id, "add_dialog_participant")) {
14825 return promise.set_error(Status::Error(400, "Chat not found"));
14826 }
14827
14828 switch (dialog_id.get_type()) {
14829 case DialogType::User:
14830 return promise.set_error(Status::Error(400, "Can't add members to a private chat"));
14831 case DialogType::Chat:
14832 return add_chat_participant(dialog_id.get_chat_id(), user_id, forward_limit, std::move(promise));
14833 case DialogType::Channel:
14834 return add_channel_participant(dialog_id.get_channel_id(), user_id, DialogParticipantStatus::Left(),
14835 std::move(promise));
14836 case DialogType::SecretChat:
14837 return promise.set_error(Status::Error(400, "Can't add members to a secret chat"));
14838 case DialogType::None:
14839 default:
14840 UNREACHABLE();
14841 }
14842 }
14843
add_dialog_participants(DialogId dialog_id,const vector<UserId> & user_ids,Promise<Unit> && promise)14844 void ContactsManager::add_dialog_participants(DialogId dialog_id, const vector<UserId> &user_ids,
14845 Promise<Unit> &&promise) {
14846 if (!td_->messages_manager_->have_dialog_force(dialog_id, "add_dialog_participants")) {
14847 return promise.set_error(Status::Error(400, "Chat not found"));
14848 }
14849
14850 switch (dialog_id.get_type()) {
14851 case DialogType::User:
14852 return promise.set_error(Status::Error(400, "Can't add members to a private chat"));
14853 case DialogType::Chat:
14854 return promise.set_error(Status::Error(400, "Can't add many members at once to a basic group chat"));
14855 case DialogType::Channel:
14856 return add_channel_participants(dialog_id.get_channel_id(), user_ids, std::move(promise));
14857 case DialogType::SecretChat:
14858 return promise.set_error(Status::Error(400, "Can't add members to a secret chat"));
14859 case DialogType::None:
14860 default:
14861 UNREACHABLE();
14862 }
14863 }
14864
set_dialog_participant_status(DialogId dialog_id,DialogId participant_dialog_id,DialogParticipantStatus && status,Promise<Unit> && promise)14865 void ContactsManager::set_dialog_participant_status(DialogId dialog_id, DialogId participant_dialog_id,
14866 DialogParticipantStatus &&status, Promise<Unit> &&promise) {
14867 if (!td_->messages_manager_->have_dialog_force(dialog_id, "set_dialog_participant_status")) {
14868 return promise.set_error(Status::Error(400, "Chat not found"));
14869 }
14870
14871 switch (dialog_id.get_type()) {
14872 case DialogType::User:
14873 return promise.set_error(Status::Error(400, "Chat member status can't be changed in private chats"));
14874 case DialogType::Chat:
14875 if (participant_dialog_id.get_type() != DialogType::User) {
14876 if (status == DialogParticipantStatus::Left()) {
14877 return promise.set_value(Unit());
14878 } else {
14879 return promise.set_error(Status::Error(400, "Chats can't be members of basic groups"));
14880 }
14881 }
14882 return set_chat_participant_status(dialog_id.get_chat_id(), participant_dialog_id.get_user_id(), status,
14883 std::move(promise));
14884 case DialogType::Channel:
14885 return set_channel_participant_status(dialog_id.get_channel_id(), participant_dialog_id, status,
14886 std::move(promise));
14887 case DialogType::SecretChat:
14888 return promise.set_error(Status::Error(400, "Chat member status can't be changed in secret chats"));
14889 case DialogType::None:
14890 default:
14891 UNREACHABLE();
14892 }
14893 }
14894
ban_dialog_participant(DialogId dialog_id,DialogId participant_dialog_id,int32 banned_until_date,bool revoke_messages,Promise<Unit> && promise)14895 void ContactsManager::ban_dialog_participant(DialogId dialog_id, DialogId participant_dialog_id,
14896 int32 banned_until_date, bool revoke_messages, Promise<Unit> &&promise) {
14897 if (!td_->messages_manager_->have_dialog_force(dialog_id, "ban_dialog_participant")) {
14898 return promise.set_error(Status::Error(400, "Chat not found"));
14899 }
14900
14901 switch (dialog_id.get_type()) {
14902 case DialogType::User:
14903 return promise.set_error(Status::Error(400, "Can't ban members in private chats"));
14904 case DialogType::Chat:
14905 if (participant_dialog_id.get_type() != DialogType::User) {
14906 return promise.set_error(Status::Error(400, "Can't ban chats in basic groups"));
14907 }
14908 return delete_chat_participant(dialog_id.get_chat_id(), participant_dialog_id.get_user_id(), revoke_messages,
14909 std::move(promise));
14910 case DialogType::Channel:
14911 return set_channel_participant_status(dialog_id.get_channel_id(), participant_dialog_id,
14912 DialogParticipantStatus::Banned(banned_until_date), std::move(promise));
14913 case DialogType::SecretChat:
14914 return promise.set_error(Status::Error(400, "Can't ban members in secret chats"));
14915 case DialogType::None:
14916 default:
14917 UNREACHABLE();
14918 }
14919 }
14920
get_dialog_participant(DialogId dialog_id,DialogId participant_dialog_id,Promise<td_api::object_ptr<td_api::chatMember>> && promise)14921 void ContactsManager::get_dialog_participant(DialogId dialog_id, DialogId participant_dialog_id,
14922 Promise<td_api::object_ptr<td_api::chatMember>> &&promise) {
14923 auto new_promise = PromiseCreator::lambda(
14924 [actor_id = actor_id(this), promise = std::move(promise)](Result<DialogParticipant> &&result) mutable {
14925 TRY_RESULT_PROMISE(promise, dialog_participant, std::move(result));
14926 send_closure(actor_id, &ContactsManager::finish_get_dialog_participant, std::move(dialog_participant),
14927 std::move(promise));
14928 });
14929 do_get_dialog_participant(dialog_id, participant_dialog_id, std::move(new_promise));
14930 }
14931
finish_get_dialog_participant(DialogParticipant && dialog_participant,Promise<td_api::object_ptr<td_api::chatMember>> && promise)14932 void ContactsManager::finish_get_dialog_participant(DialogParticipant &&dialog_participant,
14933 Promise<td_api::object_ptr<td_api::chatMember>> &&promise) {
14934 TRY_STATUS_PROMISE(promise, G()->close_status());
14935
14936 auto participant_dialog_id = dialog_participant.dialog_id_;
14937 bool is_user = participant_dialog_id.get_type() == DialogType::User;
14938 if ((is_user && !have_user(participant_dialog_id.get_user_id())) ||
14939 (!is_user && !td_->messages_manager_->have_dialog(participant_dialog_id))) {
14940 return promise.set_error(Status::Error(400, "Member not found"));
14941 }
14942
14943 promise.set_value(get_chat_member_object(dialog_participant));
14944 }
14945
do_get_dialog_participant(DialogId dialog_id,DialogId participant_dialog_id,Promise<DialogParticipant> && promise)14946 void ContactsManager::do_get_dialog_participant(DialogId dialog_id, DialogId participant_dialog_id,
14947 Promise<DialogParticipant> &&promise) {
14948 LOG(INFO) << "Receive GetChatMember request to get " << participant_dialog_id << " in " << dialog_id;
14949 if (!td_->messages_manager_->have_dialog_force(dialog_id, "do_get_dialog_participant")) {
14950 return promise.set_error(Status::Error(400, "Chat not found"));
14951 }
14952
14953 switch (dialog_id.get_type()) {
14954 case DialogType::User: {
14955 auto my_user_id = get_my_id();
14956 auto peer_user_id = dialog_id.get_user_id();
14957 if (participant_dialog_id == DialogId(my_user_id)) {
14958 return promise.set_value(DialogParticipant::private_member(my_user_id, peer_user_id));
14959 }
14960 if (participant_dialog_id == dialog_id) {
14961 return promise.set_value(DialogParticipant::private_member(peer_user_id, my_user_id));
14962 }
14963
14964 return promise.set_error(Status::Error(400, "Member not found"));
14965 }
14966 case DialogType::Chat:
14967 if (participant_dialog_id.get_type() != DialogType::User) {
14968 return promise.set_value(DialogParticipant::left(participant_dialog_id));
14969 }
14970 return get_chat_participant(dialog_id.get_chat_id(), participant_dialog_id.get_user_id(), std::move(promise));
14971 case DialogType::Channel:
14972 return get_channel_participant(dialog_id.get_channel_id(), participant_dialog_id, std::move(promise));
14973 case DialogType::SecretChat: {
14974 auto my_user_id = get_my_id();
14975 auto peer_user_id = get_secret_chat_user_id(dialog_id.get_secret_chat_id());
14976 if (participant_dialog_id == DialogId(my_user_id)) {
14977 return promise.set_value(DialogParticipant::private_member(my_user_id, peer_user_id));
14978 }
14979 if (peer_user_id.is_valid() && participant_dialog_id == DialogId(peer_user_id)) {
14980 return promise.set_value(DialogParticipant::private_member(peer_user_id, my_user_id));
14981 }
14982
14983 return promise.set_error(Status::Error(400, "Member not found"));
14984 }
14985 case DialogType::None:
14986 default:
14987 UNREACHABLE();
14988 return promise.set_error(Status::Error(500, "Wrong chat type"));
14989 }
14990 }
14991
search_private_chat_participants(UserId my_user_id,UserId peer_user_id,const string & query,int32 limit,DialogParticipantsFilter filter) const14992 DialogParticipants ContactsManager::search_private_chat_participants(UserId my_user_id, UserId peer_user_id,
14993 const string &query, int32 limit,
14994 DialogParticipantsFilter filter) const {
14995 vector<DialogId> dialog_ids;
14996 if (filter.is_dialog_participant_suitable(td_, DialogParticipant::private_member(my_user_id, peer_user_id))) {
14997 dialog_ids.push_back(DialogId(my_user_id));
14998 }
14999 if (peer_user_id.is_valid() && peer_user_id != my_user_id &&
15000 filter.is_dialog_participant_suitable(td_, DialogParticipant::private_member(peer_user_id, my_user_id))) {
15001 dialog_ids.push_back(DialogId(peer_user_id));
15002 }
15003
15004 auto result = search_among_dialogs(dialog_ids, query, limit);
15005 return {result.first, transform(result.second, [&](DialogId dialog_id) {
15006 auto user_id = dialog_id.get_user_id();
15007 return DialogParticipant::private_member(user_id, user_id == my_user_id ? peer_user_id : my_user_id);
15008 })};
15009 }
15010
search_dialog_participants(DialogId dialog_id,const string & query,int32 limit,DialogParticipantsFilter filter,Promise<DialogParticipants> && promise)15011 void ContactsManager::search_dialog_participants(DialogId dialog_id, const string &query, int32 limit,
15012 DialogParticipantsFilter filter,
15013 Promise<DialogParticipants> &&promise) {
15014 LOG(INFO) << "Receive searchChatMembers request to search for \"" << query << "\" in " << dialog_id << " with filter "
15015 << filter;
15016 if (!td_->messages_manager_->have_dialog_force(dialog_id, "search_dialog_participants")) {
15017 return promise.set_error(Status::Error(400, "Chat not found"));
15018 }
15019 if (limit < 0) {
15020 return promise.set_error(Status::Error(400, "Parameter limit must be non-negative"));
15021 }
15022
15023 switch (dialog_id.get_type()) {
15024 case DialogType::User:
15025 promise.set_value(search_private_chat_participants(get_my_id(), dialog_id.get_user_id(), query, limit, filter));
15026 return;
15027 case DialogType::Chat:
15028 return search_chat_participants(dialog_id.get_chat_id(), query, limit, filter, std::move(promise));
15029 case DialogType::Channel: {
15030 auto channel_id = dialog_id.get_channel_id();
15031 if (filter.has_query()) {
15032 return get_channel_participants(channel_id, filter.get_supergroup_members_filter_object(query), string(), 0,
15033 limit, 0, std::move(promise));
15034 } else {
15035 return get_channel_participants(channel_id, filter.get_supergroup_members_filter_object(string()), query, 0,
15036 100, limit, std::move(promise));
15037 }
15038 }
15039 case DialogType::SecretChat: {
15040 auto peer_user_id = get_secret_chat_user_id(dialog_id.get_secret_chat_id());
15041 promise.set_value(search_private_chat_participants(get_my_id(), peer_user_id, query, limit, filter));
15042 return;
15043 }
15044 case DialogType::None:
15045 default:
15046 UNREACHABLE();
15047 promise.set_error(Status::Error(500, "Wrong chat type"));
15048 }
15049 }
15050
get_chat_participant(ChatId chat_id,UserId user_id,Promise<DialogParticipant> && promise)15051 void ContactsManager::get_chat_participant(ChatId chat_id, UserId user_id, Promise<DialogParticipant> &&promise) {
15052 LOG(INFO) << "Trying to get " << user_id << " as member of " << chat_id;
15053
15054 auto c = get_chat(chat_id);
15055 if (c == nullptr) {
15056 return promise.set_error(Status::Error(400, "Group not found"));
15057 }
15058
15059 auto chat_full = get_chat_full_force(chat_id, "get_chat_participant");
15060 if (chat_full == nullptr || (td_->auth_manager_->is_bot() && is_chat_full_outdated(chat_full, c, chat_id))) {
15061 auto query_promise = PromiseCreator::lambda(
15062 [actor_id = actor_id(this), chat_id, user_id, promise = std::move(promise)](Result<Unit> &&result) mutable {
15063 TRY_STATUS_PROMISE(promise, std::move(result));
15064 send_closure(actor_id, &ContactsManager::finish_get_chat_participant, chat_id, user_id, std::move(promise));
15065 });
15066 send_get_chat_full_query(chat_id, std::move(query_promise), "get_chat_participant");
15067 return;
15068 }
15069
15070 if (is_chat_full_outdated(chat_full, c, chat_id)) {
15071 send_get_chat_full_query(chat_id, Auto(), "get_chat_participant lazy");
15072 }
15073
15074 finish_get_chat_participant(chat_id, user_id, std::move(promise));
15075 }
15076
finish_get_chat_participant(ChatId chat_id,UserId user_id,Promise<DialogParticipant> && promise)15077 void ContactsManager::finish_get_chat_participant(ChatId chat_id, UserId user_id,
15078 Promise<DialogParticipant> &&promise) {
15079 TRY_STATUS_PROMISE(promise, G()->close_status());
15080
15081 const auto *participant = get_chat_participant(chat_id, user_id);
15082 if (participant == nullptr) {
15083 return promise.set_value(DialogParticipant::left(DialogId(user_id)));
15084 }
15085
15086 promise.set_value(DialogParticipant(*participant));
15087 }
15088
search_chat_participants(ChatId chat_id,const string & query,int32 limit,DialogParticipantsFilter filter,Promise<DialogParticipants> && promise)15089 void ContactsManager::search_chat_participants(ChatId chat_id, const string &query, int32 limit,
15090 DialogParticipantsFilter filter, Promise<DialogParticipants> &&promise) {
15091 if (limit < 0) {
15092 return promise.set_error(Status::Error(400, "Parameter limit must be non-negative"));
15093 }
15094
15095 auto load_chat_full_promise = PromiseCreator::lambda([actor_id = actor_id(this), chat_id, query, limit, filter,
15096 promise = std::move(promise)](Result<Unit> &&result) mutable {
15097 if (result.is_error()) {
15098 promise.set_error(result.move_as_error());
15099 } else {
15100 send_closure(actor_id, &ContactsManager::do_search_chat_participants, chat_id, query, limit, filter,
15101 std::move(promise));
15102 }
15103 });
15104 load_chat_full(chat_id, false, std::move(load_chat_full_promise), "search_chat_participants");
15105 }
15106
do_search_chat_participants(ChatId chat_id,const string & query,int32 limit,DialogParticipantsFilter filter,Promise<DialogParticipants> && promise)15107 void ContactsManager::do_search_chat_participants(ChatId chat_id, const string &query, int32 limit,
15108 DialogParticipantsFilter filter,
15109 Promise<DialogParticipants> &&promise) {
15110 TRY_STATUS_PROMISE(promise, G()->close_status());
15111
15112 auto chat_full = get_chat_full(chat_id);
15113 if (chat_full == nullptr) {
15114 return promise.set_error(Status::Error(500, "Can't find basic group full info"));
15115 }
15116
15117 vector<DialogId> dialog_ids;
15118 for (const auto &participant : chat_full->participants) {
15119 if (filter.is_dialog_participant_suitable(td_, participant)) {
15120 dialog_ids.push_back(participant.dialog_id_);
15121 }
15122 }
15123
15124 int32 total_count;
15125 std::tie(total_count, dialog_ids) = search_among_dialogs(dialog_ids, query, limit);
15126 promise.set_value(DialogParticipants{total_count, transform(dialog_ids, [chat_full](DialogId dialog_id) {
15127 return *ContactsManager::get_chat_full_participant(chat_full, dialog_id);
15128 })});
15129 }
15130
get_channel_participant(ChannelId channel_id,DialogId participant_dialog_id,Promise<DialogParticipant> && promise)15131 void ContactsManager::get_channel_participant(ChannelId channel_id, DialogId participant_dialog_id,
15132 Promise<DialogParticipant> &&promise) {
15133 LOG(INFO) << "Trying to get " << participant_dialog_id << " as member of " << channel_id;
15134
15135 auto input_peer = td_->messages_manager_->get_input_peer(participant_dialog_id, AccessRights::Read);
15136 if (input_peer == nullptr) {
15137 return promise.set_error(Status::Error(400, "User not found"));
15138 }
15139
15140 if (have_channel_participant_cache(channel_id)) {
15141 auto *participant = get_channel_participant_from_cache(channel_id, participant_dialog_id);
15142 if (participant != nullptr) {
15143 return promise.set_value(DialogParticipant{*participant});
15144 }
15145 }
15146
15147 auto on_result_promise = PromiseCreator::lambda([actor_id = actor_id(this), channel_id, promise = std::move(promise)](
15148 Result<DialogParticipant> r_dialog_participant) mutable {
15149 TRY_RESULT_PROMISE(promise, dialog_participant, std::move(r_dialog_participant));
15150 send_closure(actor_id, &ContactsManager::finish_get_channel_participant, channel_id, std::move(dialog_participant),
15151 std::move(promise));
15152 });
15153
15154 td_->create_handler<GetChannelParticipantQuery>(std::move(on_result_promise))
15155 ->send(channel_id, participant_dialog_id, std::move(input_peer));
15156 }
15157
finish_get_channel_participant(ChannelId channel_id,DialogParticipant && dialog_participant,Promise<DialogParticipant> && promise)15158 void ContactsManager::finish_get_channel_participant(ChannelId channel_id, DialogParticipant &&dialog_participant,
15159 Promise<DialogParticipant> &&promise) {
15160 TRY_STATUS_PROMISE(promise, G()->close_status());
15161
15162 LOG(INFO) << "Receive a member " << dialog_participant.dialog_id_ << " of a channel " << channel_id;
15163
15164 dialog_participant.status_.update_restrictions();
15165 if (have_channel_participant_cache(channel_id)) {
15166 add_channel_participant_to_cache(channel_id, dialog_participant, false);
15167 }
15168 promise.set_value(std::move(dialog_participant));
15169 }
15170
get_channel_participants(ChannelId channel_id,tl_object_ptr<td_api::SupergroupMembersFilter> && filter,string additional_query,int32 offset,int32 limit,int32 additional_limit,Promise<DialogParticipants> && promise)15171 void ContactsManager::get_channel_participants(ChannelId channel_id,
15172 tl_object_ptr<td_api::SupergroupMembersFilter> &&filter,
15173 string additional_query, int32 offset, int32 limit,
15174 int32 additional_limit, Promise<DialogParticipants> &&promise) {
15175 if (limit <= 0) {
15176 return promise.set_error(Status::Error(400, "Parameter limit must be positive"));
15177 }
15178 if (limit > MAX_GET_CHANNEL_PARTICIPANTS) {
15179 limit = MAX_GET_CHANNEL_PARTICIPANTS;
15180 }
15181
15182 if (offset < 0) {
15183 return promise.set_error(Status::Error(400, "Parameter offset must be non-negative"));
15184 }
15185
15186 auto channel_full = get_channel_full_force(channel_id, false, "get_channel_participants");
15187 if (channel_full != nullptr && !channel_full->is_expired() && !channel_full->can_get_participants) {
15188 return promise.set_error(Status::Error(400, "Member list is inaccessible"));
15189 }
15190
15191 ChannelParticipantsFilter participants_filter(filter);
15192 auto get_channel_participants_promise = PromiseCreator::lambda(
15193 [actor_id = actor_id(this), channel_id, filter = participants_filter,
15194 additional_query = std::move(additional_query), offset, limit, additional_limit, promise = std::move(promise)](
15195 Result<tl_object_ptr<telegram_api::channels_channelParticipants>> &&result) mutable {
15196 if (result.is_error()) {
15197 promise.set_error(result.move_as_error());
15198 } else {
15199 send_closure(actor_id, &ContactsManager::on_get_channel_participants, channel_id, std::move(filter), offset,
15200 limit, std::move(additional_query), additional_limit, result.move_as_ok(), std::move(promise));
15201 }
15202 });
15203 td_->create_handler<GetChannelParticipantsQuery>(std::move(get_channel_participants_promise))
15204 ->send(channel_id, participants_filter, offset, limit);
15205 }
15206
get_dialog_administrators(DialogId dialog_id,int left_tries,Promise<Unit> && promise)15207 vector<DialogAdministrator> ContactsManager::get_dialog_administrators(DialogId dialog_id, int left_tries,
15208 Promise<Unit> &&promise) {
15209 LOG(INFO) << "Receive GetChatAdministrators request in " << dialog_id << " with " << left_tries << " left tries";
15210 if (!td_->messages_manager_->have_dialog_force(dialog_id, "get_dialog_administrators")) {
15211 promise.set_error(Status::Error(400, "Chat not found"));
15212 return {};
15213 }
15214
15215 switch (dialog_id.get_type()) {
15216 case DialogType::User:
15217 case DialogType::SecretChat:
15218 promise.set_value(Unit());
15219 return {};
15220 case DialogType::Chat:
15221 case DialogType::Channel:
15222 break;
15223 case DialogType::None:
15224 default:
15225 UNREACHABLE();
15226 return {};
15227 }
15228
15229 auto it = dialog_administrators_.find(dialog_id);
15230 if (it != dialog_administrators_.end()) {
15231 promise.set_value(Unit());
15232 if (left_tries >= 2) {
15233 auto hash = get_vector_hash(transform(it->second, [](const DialogAdministrator &administrator) {
15234 return static_cast<uint64>(administrator.get_user_id().get());
15235 }));
15236 reload_dialog_administrators(dialog_id, hash, Auto()); // update administrators cache
15237 }
15238 return it->second;
15239 }
15240
15241 if (left_tries >= 3) {
15242 load_dialog_administrators(dialog_id, std::move(promise));
15243 return {};
15244 }
15245
15246 if (left_tries >= 2) {
15247 reload_dialog_administrators(dialog_id, 0, std::move(promise));
15248 return {};
15249 }
15250
15251 LOG(ERROR) << "Have no known administrators in " << dialog_id;
15252 promise.set_value(Unit());
15253 return {};
15254 }
15255
get_dialog_administrators_database_key(DialogId dialog_id)15256 string ContactsManager::get_dialog_administrators_database_key(DialogId dialog_id) {
15257 return PSTRING() << "adm" << (-dialog_id.get());
15258 }
15259
load_dialog_administrators(DialogId dialog_id,Promise<Unit> && promise)15260 void ContactsManager::load_dialog_administrators(DialogId dialog_id, Promise<Unit> &&promise) {
15261 if (G()->parameters().use_chat_info_db) {
15262 LOG(INFO) << "Load administrators of " << dialog_id << " from database";
15263 G()->td_db()->get_sqlite_pmc()->get(get_dialog_administrators_database_key(dialog_id),
15264 PromiseCreator::lambda([actor_id = actor_id(this), dialog_id,
15265 promise = std::move(promise)](string value) mutable {
15266 send_closure(actor_id,
15267 &ContactsManager::on_load_dialog_administrators_from_database,
15268 dialog_id, std::move(value), std::move(promise));
15269 }));
15270 } else {
15271 promise.set_value(Unit());
15272 }
15273 }
15274
on_load_dialog_administrators_from_database(DialogId dialog_id,string value,Promise<Unit> && promise)15275 void ContactsManager::on_load_dialog_administrators_from_database(DialogId dialog_id, string value,
15276 Promise<Unit> &&promise) {
15277 if (value.empty() || G()->close_flag()) {
15278 promise.set_value(Unit());
15279 return;
15280 }
15281
15282 vector<DialogAdministrator> administrators;
15283 log_event_parse(administrators, value).ensure();
15284
15285 LOG(INFO) << "Successfully loaded " << administrators.size() << " administrators in " << dialog_id
15286 << " from database";
15287
15288 MultiPromiseActorSafe load_users_multipromise{"LoadUsersMultiPromiseActor"};
15289 load_users_multipromise.add_promise(
15290 PromiseCreator::lambda([actor_id = actor_id(this), dialog_id, administrators,
15291 promise = std::move(promise)](Result<Unit> result) mutable {
15292 send_closure(actor_id, &ContactsManager::on_load_administrator_users_finished, dialog_id,
15293 std::move(administrators), std::move(result), std::move(promise));
15294 }));
15295
15296 auto lock_promise = load_users_multipromise.get_promise();
15297
15298 for (auto &administrator : administrators) {
15299 get_user(administrator.get_user_id(), 3, load_users_multipromise.get_promise());
15300 }
15301
15302 lock_promise.set_value(Unit());
15303 }
15304
on_load_administrator_users_finished(DialogId dialog_id,vector<DialogAdministrator> administrators,Result<> result,Promise<Unit> promise)15305 void ContactsManager::on_load_administrator_users_finished(DialogId dialog_id,
15306 vector<DialogAdministrator> administrators, Result<> result,
15307 Promise<Unit> promise) {
15308 if (!G()->close_flag() && result.is_ok()) {
15309 dialog_administrators_.emplace(dialog_id, std::move(administrators));
15310 }
15311 promise.set_value(Unit());
15312 }
15313
on_update_channel_administrator_count(ChannelId channel_id,int32 administrator_count)15314 void ContactsManager::on_update_channel_administrator_count(ChannelId channel_id, int32 administrator_count) {
15315 auto channel_full = get_channel_full_force(channel_id, true, "on_update_channel_administrator_count");
15316 if (channel_full != nullptr && channel_full->administrator_count != administrator_count) {
15317 channel_full->administrator_count = administrator_count;
15318 channel_full->is_changed = true;
15319
15320 if (channel_full->participant_count < channel_full->administrator_count) {
15321 channel_full->participant_count = channel_full->administrator_count;
15322
15323 auto c = get_channel(channel_id);
15324 if (c != nullptr && c->participant_count != channel_full->participant_count) {
15325 c->participant_count = channel_full->participant_count;
15326 c->is_changed = true;
15327 update_channel(c, channel_id);
15328 }
15329 }
15330
15331 update_channel_full(channel_full, channel_id, "on_update_channel_administrator_count");
15332 }
15333 }
15334
on_update_dialog_administrators(DialogId dialog_id,vector<DialogAdministrator> && administrators,bool have_access,bool from_database)15335 void ContactsManager::on_update_dialog_administrators(DialogId dialog_id, vector<DialogAdministrator> &&administrators,
15336 bool have_access, bool from_database) {
15337 LOG(INFO) << "Update administrators in " << dialog_id << " to " << format::as_array(administrators);
15338 if (have_access) {
15339 std::sort(administrators.begin(), administrators.end(),
15340 [](const DialogAdministrator &lhs, const DialogAdministrator &rhs) {
15341 return lhs.get_user_id().get() < rhs.get_user_id().get();
15342 });
15343
15344 auto it = dialog_administrators_.find(dialog_id);
15345 if (it != dialog_administrators_.end()) {
15346 if (it->second == administrators) {
15347 return;
15348 }
15349 it->second = std::move(administrators);
15350 } else {
15351 it = dialog_administrators_.emplace(dialog_id, std::move(administrators)).first;
15352 }
15353
15354 if (G()->parameters().use_chat_info_db && !from_database) {
15355 LOG(INFO) << "Save administrators of " << dialog_id << " to database";
15356 G()->td_db()->get_sqlite_pmc()->set(get_dialog_administrators_database_key(dialog_id),
15357 log_event_store(it->second).as_slice().str(), Auto());
15358 }
15359 } else {
15360 dialog_administrators_.erase(dialog_id);
15361 if (G()->parameters().use_chat_info_db) {
15362 G()->td_db()->get_sqlite_pmc()->erase(get_dialog_administrators_database_key(dialog_id), Auto());
15363 }
15364 }
15365 }
15366
reload_dialog_administrators(DialogId dialog_id,int64 hash,Promise<Unit> && promise)15367 void ContactsManager::reload_dialog_administrators(DialogId dialog_id, int64 hash, Promise<Unit> &&promise) {
15368 switch (dialog_id.get_type()) {
15369 case DialogType::Chat:
15370 load_chat_full(dialog_id.get_chat_id(), false, std::move(promise), "reload_dialog_administrators");
15371 break;
15372 case DialogType::Channel:
15373 td_->create_handler<GetChannelAdministratorsQuery>(std::move(promise))->send(dialog_id.get_channel_id(), hash);
15374 break;
15375 default:
15376 UNREACHABLE();
15377 }
15378 }
15379
on_chat_update(telegram_api::chatEmpty & chat,const char * source)15380 void ContactsManager::on_chat_update(telegram_api::chatEmpty &chat, const char *source) {
15381 ChatId chat_id(chat.id_);
15382 if (!chat_id.is_valid()) {
15383 LOG(ERROR) << "Receive invalid " << chat_id << " from " << source;
15384 return;
15385 }
15386
15387 if (!have_chat(chat_id)) {
15388 LOG(ERROR) << "Have no information about " << chat_id << " but received chatEmpty from " << source;
15389 }
15390 }
15391
on_chat_update(telegram_api::chat & chat,const char * source)15392 void ContactsManager::on_chat_update(telegram_api::chat &chat, const char *source) {
15393 auto debug_str = PSTRING() << " from " << source << " in " << oneline(to_string(chat));
15394 ChatId chat_id(chat.id_);
15395 if (!chat_id.is_valid()) {
15396 LOG(ERROR) << "Receive invalid " << chat_id << debug_str;
15397 return;
15398 }
15399
15400 DialogParticipantStatus status = [&] {
15401 bool is_creator = 0 != (chat.flags_ & CHAT_FLAG_USER_IS_CREATOR);
15402 bool has_left = 0 != (chat.flags_ & CHAT_FLAG_USER_HAS_LEFT);
15403 bool was_kicked = 0 != (chat.flags_ & CHAT_FLAG_USER_WAS_KICKED);
15404 if (was_kicked) {
15405 LOG_IF(ERROR, has_left) << "Kicked and left" << debug_str; // only one of the flags can be set
15406 has_left = true;
15407 }
15408
15409 if (is_creator) {
15410 return DialogParticipantStatus::Creator(!has_left, false, string());
15411 } else if (chat.admin_rights_ != nullptr) {
15412 return get_dialog_participant_status(false, std::move(chat.admin_rights_), string());
15413 } else if (was_kicked) {
15414 return DialogParticipantStatus::Banned(0);
15415 } else if (has_left) {
15416 return DialogParticipantStatus::Left();
15417 } else {
15418 return DialogParticipantStatus::Member();
15419 }
15420 }();
15421
15422 bool is_active = 0 == (chat.flags_ & CHAT_FLAG_IS_DEACTIVATED);
15423
15424 ChannelId migrated_to_channel_id;
15425 if (chat.flags_ & CHAT_FLAG_WAS_MIGRATED) {
15426 switch (chat.migrated_to_->get_id()) {
15427 case telegram_api::inputChannelEmpty::ID: {
15428 LOG(ERROR) << "Receive empty upgraded to supergroup for " << chat_id << debug_str;
15429 break;
15430 }
15431 case telegram_api::inputChannel::ID: {
15432 auto input_channel = move_tl_object_as<telegram_api::inputChannel>(chat.migrated_to_);
15433 migrated_to_channel_id = ChannelId(input_channel->channel_id_);
15434 if (!have_channel_force(migrated_to_channel_id)) {
15435 if (!migrated_to_channel_id.is_valid()) {
15436 LOG(ERROR) << "Receive invalid " << migrated_to_channel_id << debug_str;
15437 } else {
15438 // temporarily create the channel
15439 Channel *c = add_channel(migrated_to_channel_id, "on_chat_update");
15440 c->access_hash = input_channel->access_hash_;
15441 c->title = chat.title_;
15442 c->status = DialogParticipantStatus::Left();
15443 c->is_megagroup = true;
15444
15445 // we definitely need to call update_channel, because client should know about every added channel
15446 update_channel(c, migrated_to_channel_id);
15447
15448 // get info about the channel
15449 td_->create_handler<GetChannelsQuery>(Promise<>())->send(std::move(input_channel));
15450 }
15451 }
15452 break;
15453 }
15454 default:
15455 UNREACHABLE();
15456 }
15457 }
15458
15459 Chat *c = get_chat_force(chat_id); // to load versions
15460 if (c == nullptr) {
15461 c = add_chat(chat_id);
15462 }
15463 on_update_chat_title(c, chat_id, std::move(chat.title_));
15464 if (!status.is_left()) {
15465 on_update_chat_participant_count(c, chat_id, chat.participants_count_, chat.version_, debug_str);
15466 }
15467 if (c->date != chat.date_) {
15468 LOG_IF(ERROR, c->date != 0) << "Chat creation date has changed from " << c->date << " to " << chat.date_
15469 << debug_str;
15470 c->date = chat.date_;
15471 c->need_save_to_database = true;
15472 }
15473 on_update_chat_status(c, chat_id, std::move(status));
15474 on_update_chat_default_permissions(c, chat_id, get_restricted_rights(std::move(chat.default_banned_rights_)),
15475 chat.version_);
15476 on_update_chat_photo(c, chat_id, std::move(chat.photo_));
15477 on_update_chat_active(c, chat_id, is_active);
15478 on_update_chat_noforwards(c, chat_id, chat.noforwards_);
15479 on_update_chat_migrated_to_channel_id(c, chat_id, migrated_to_channel_id);
15480 LOG_IF(INFO, !is_active && !migrated_to_channel_id.is_valid()) << chat_id << " is deactivated" << debug_str;
15481 if (c->cache_version != Chat::CACHE_VERSION) {
15482 c->cache_version = Chat::CACHE_VERSION;
15483 c->need_save_to_database = true;
15484 }
15485 c->is_received_from_server = true;
15486 update_chat(c, chat_id);
15487
15488 bool has_active_group_call = (chat.flags_ & CHAT_FLAG_HAS_ACTIVE_GROUP_CALL) != 0;
15489 bool is_group_call_empty = (chat.flags_ & CHAT_FLAG_IS_GROUP_CALL_NON_EMPTY) == 0;
15490 td_->messages_manager_->on_update_dialog_group_call(DialogId(chat_id), has_active_group_call, is_group_call_empty,
15491 "receive chat");
15492 }
15493
on_chat_update(telegram_api::chatForbidden & chat,const char * source)15494 void ContactsManager::on_chat_update(telegram_api::chatForbidden &chat, const char *source) {
15495 ChatId chat_id(chat.id_);
15496 if (!chat_id.is_valid()) {
15497 LOG(ERROR) << "Receive invalid " << chat_id << " from " << source;
15498 return;
15499 }
15500
15501 bool is_uninited = get_chat_force(chat_id) == nullptr;
15502 Chat *c = add_chat(chat_id);
15503 on_update_chat_title(c, chat_id, std::move(chat.title_));
15504 // chat participant count will be updated in on_update_chat_status
15505 on_update_chat_photo(c, chat_id, nullptr);
15506 if (c->date != 0) {
15507 c->date = 0; // removed in 38-th layer
15508 c->need_save_to_database = true;
15509 }
15510 on_update_chat_status(c, chat_id, DialogParticipantStatus::Banned(0));
15511 if (is_uninited) {
15512 on_update_chat_active(c, chat_id, true);
15513 on_update_chat_migrated_to_channel_id(c, chat_id, ChannelId());
15514 } else {
15515 // leave active and migrated to as is
15516 }
15517 if (c->cache_version != Chat::CACHE_VERSION) {
15518 c->cache_version = Chat::CACHE_VERSION;
15519 c->need_save_to_database = true;
15520 }
15521 c->is_received_from_server = true;
15522 update_chat(c, chat_id);
15523 }
15524
on_chat_update(telegram_api::channel & channel,const char * source)15525 void ContactsManager::on_chat_update(telegram_api::channel &channel, const char *source) {
15526 ChannelId channel_id(channel.id_);
15527 if (!channel_id.is_valid()) {
15528 LOG(ERROR) << "Receive invalid " << channel_id << " from " << source << ": " << to_string(channel);
15529 return;
15530 }
15531
15532 if (channel.flags_ == 0 && channel.access_hash_ == 0 && channel.title_.empty()) {
15533 Channel *c = get_channel_force(channel_id);
15534 LOG(ERROR) << "Receive empty " << to_string(channel) << " from " << source << ", have "
15535 << to_string(get_supergroup_object(channel_id, c));
15536 if (c == nullptr) {
15537 min_channels_.insert(channel_id);
15538 }
15539 return;
15540 }
15541
15542 bool is_min = (channel.flags_ & CHANNEL_FLAG_IS_MIN) != 0;
15543 bool has_access_hash = (channel.flags_ & CHANNEL_FLAG_HAS_ACCESS_HASH) != 0;
15544 auto access_hash = has_access_hash ? channel.access_hash_ : 0;
15545
15546 bool has_linked_channel = (channel.flags_ & CHANNEL_FLAG_HAS_LINKED_CHAT) != 0;
15547 bool sign_messages = (channel.flags_ & CHANNEL_FLAG_SIGN_MESSAGES) != 0;
15548 bool is_slow_mode_enabled = (channel.flags_ & CHANNEL_FLAG_IS_SLOW_MODE_ENABLED) != 0;
15549 bool is_megagroup = (channel.flags_ & CHANNEL_FLAG_IS_MEGAGROUP) != 0;
15550 bool is_verified = (channel.flags_ & CHANNEL_FLAG_IS_VERIFIED) != 0;
15551 auto restriction_reasons = get_restriction_reasons(std::move(channel.restriction_reason_));
15552 bool is_scam = (channel.flags_ & CHANNEL_FLAG_IS_SCAM) != 0;
15553 bool is_fake = (channel.flags_ & CHANNEL_FLAG_IS_FAKE) != 0;
15554 bool is_gigagroup = (channel.flags_ & CHANNEL_FLAG_IS_GIGAGROUP) != 0;
15555 bool have_participant_count = (channel.flags_ & CHANNEL_FLAG_HAS_PARTICIPANT_COUNT) != 0;
15556 int32 participant_count = have_participant_count ? channel.participants_count_ : 0;
15557
15558 if (have_participant_count) {
15559 auto channel_full = get_channel_full_const(channel_id);
15560 if (channel_full != nullptr && channel_full->administrator_count > participant_count) {
15561 participant_count = channel_full->administrator_count;
15562 }
15563 }
15564
15565 {
15566 bool is_broadcast = (channel.flags_ & CHANNEL_FLAG_IS_BROADCAST) != 0;
15567 LOG_IF(ERROR, is_broadcast == is_megagroup)
15568 << "Receive wrong channel flag is_broadcast == is_megagroup == " << is_megagroup << " from " << source << ": "
15569 << oneline(to_string(channel));
15570 }
15571
15572 if (is_megagroup) {
15573 LOG_IF(ERROR, sign_messages) << "Need to sign messages in the supergroup " << channel_id << " from " << source;
15574 sign_messages = true;
15575 } else {
15576 LOG_IF(ERROR, is_slow_mode_enabled) << "Slow mode enabled in the " << channel_id << " from " << source;
15577 LOG_IF(ERROR, is_gigagroup) << "Receive broadcast group as channel " << channel_id << " from " << source;
15578 is_slow_mode_enabled = false;
15579 is_gigagroup = false;
15580 }
15581 if (is_gigagroup) {
15582 remove_dialog_suggested_action(SuggestedAction{SuggestedAction::Type::ConvertToGigagroup, DialogId(channel_id)});
15583 }
15584
15585 DialogParticipantStatus status = [&] {
15586 bool has_left = (channel.flags_ & CHANNEL_FLAG_USER_HAS_LEFT) != 0;
15587 bool is_creator = (channel.flags_ & CHANNEL_FLAG_USER_IS_CREATOR) != 0;
15588
15589 if (is_creator) {
15590 bool is_anonymous = channel.admin_rights_ != nullptr &&
15591 (channel.admin_rights_->flags_ & telegram_api::chatAdminRights::ANONYMOUS_MASK) != 0;
15592 return DialogParticipantStatus::Creator(!has_left, is_anonymous, string());
15593 } else if (channel.admin_rights_ != nullptr) {
15594 return get_dialog_participant_status(false, std::move(channel.admin_rights_), string());
15595 } else if (channel.banned_rights_ != nullptr) {
15596 return get_dialog_participant_status(!has_left, std::move(channel.banned_rights_));
15597 } else if (has_left) {
15598 return DialogParticipantStatus::Left();
15599 } else {
15600 return DialogParticipantStatus::Member();
15601 }
15602 }();
15603
15604 if (is_min) {
15605 // TODO there can be better support for min channels
15606 Channel *c = get_channel_force(channel_id);
15607 if (c != nullptr) {
15608 LOG(DEBUG) << "Receive known min " << channel_id;
15609 on_update_channel_title(c, channel_id, std::move(channel.title_));
15610 on_update_channel_username(c, channel_id, std::move(channel.username_));
15611 on_update_channel_photo(c, channel_id, std::move(channel.photo_));
15612 on_update_channel_default_permissions(c, channel_id,
15613 get_restricted_rights(std::move(channel.default_banned_rights_)));
15614 on_update_channel_has_location(c, channel_id, channel.has_geo_);
15615 on_update_channel_noforwards(c, channel_id, channel.noforwards_);
15616
15617 if (c->has_linked_channel != has_linked_channel || c->is_slow_mode_enabled != is_slow_mode_enabled ||
15618 c->is_megagroup != is_megagroup || c->restriction_reasons != restriction_reasons || c->is_scam != is_scam ||
15619 c->is_fake != is_fake || c->is_gigagroup != is_gigagroup) {
15620 c->has_linked_channel = has_linked_channel;
15621 c->is_slow_mode_enabled = is_slow_mode_enabled;
15622 c->is_megagroup = is_megagroup;
15623 c->restriction_reasons = std::move(restriction_reasons);
15624 c->is_scam = is_scam;
15625 c->is_fake = is_fake;
15626 c->is_gigagroup = is_gigagroup;
15627
15628 c->is_changed = true;
15629 invalidate_channel_full(channel_id, !c->is_slow_mode_enabled);
15630 }
15631 if (c->is_verified != is_verified || c->sign_messages != sign_messages) {
15632 c->is_verified = is_verified;
15633 c->sign_messages = sign_messages;
15634
15635 c->is_changed = true;
15636 }
15637
15638 update_channel(c, channel_id);
15639 } else {
15640 min_channels_.insert(channel_id);
15641 }
15642 return;
15643 }
15644 if (!has_access_hash) {
15645 LOG(ERROR) << "Receive non-min " << channel_id << " without access_hash from " << source;
15646 return;
15647 }
15648
15649 if (status.is_creator()) {
15650 // to correctly calculate is_ownership_transferred in on_update_channel_status
15651 get_channel_force(channel_id);
15652 }
15653
15654 Channel *c = add_channel(channel_id, "on_channel");
15655 if (c->status.is_banned()) { // possibly uninited channel
15656 min_channels_.erase(channel_id);
15657 }
15658 if (c->access_hash != access_hash) {
15659 c->access_hash = access_hash;
15660 c->need_save_to_database = true;
15661 }
15662 on_update_channel_title(c, channel_id, std::move(channel.title_));
15663 if (c->date != channel.date_) {
15664 c->date = channel.date_;
15665 c->is_changed = true;
15666 }
15667 on_update_channel_photo(c, channel_id, std::move(channel.photo_));
15668 on_update_channel_status(c, channel_id, std::move(status));
15669 on_update_channel_username(c, channel_id, std::move(channel.username_)); // uses status, must be called after
15670 on_update_channel_default_permissions(c, channel_id,
15671 get_restricted_rights(std::move(channel.default_banned_rights_)));
15672 on_update_channel_has_location(c, channel_id, channel.has_geo_);
15673 on_update_channel_noforwards(c, channel_id, channel.noforwards_);
15674
15675 bool need_update_participant_count = have_participant_count && participant_count != c->participant_count;
15676 if (need_update_participant_count) {
15677 c->participant_count = participant_count;
15678 c->is_changed = true;
15679 }
15680
15681 bool need_invalidate_channel_full = false;
15682 if (c->has_linked_channel != has_linked_channel || c->is_slow_mode_enabled != is_slow_mode_enabled ||
15683 c->is_megagroup != is_megagroup || c->restriction_reasons != restriction_reasons || c->is_scam != is_scam ||
15684 c->is_fake != is_fake || c->is_gigagroup != is_gigagroup) {
15685 c->has_linked_channel = has_linked_channel;
15686 c->is_slow_mode_enabled = is_slow_mode_enabled;
15687 c->is_megagroup = is_megagroup;
15688 c->restriction_reasons = std::move(restriction_reasons);
15689 c->is_scam = is_scam;
15690 c->is_fake = is_fake;
15691 c->is_gigagroup = is_gigagroup;
15692
15693 c->is_changed = true;
15694 need_invalidate_channel_full = true;
15695 }
15696 if (c->is_verified != is_verified || c->sign_messages != sign_messages) {
15697 c->is_verified = is_verified;
15698 c->sign_messages = sign_messages;
15699
15700 c->is_changed = true;
15701 }
15702
15703 if (c->cache_version != Channel::CACHE_VERSION) {
15704 c->cache_version = Channel::CACHE_VERSION;
15705 c->need_save_to_database = true;
15706 }
15707 c->is_received_from_server = true;
15708 update_channel(c, channel_id);
15709
15710 if (need_update_participant_count) {
15711 auto channel_full = get_channel_full(channel_id, true, "on_chat_update");
15712 if (channel_full != nullptr && channel_full->participant_count != participant_count) {
15713 channel_full->participant_count = participant_count;
15714 channel_full->is_changed = true;
15715 update_channel_full(channel_full, channel_id, "on_chat_update");
15716 }
15717 }
15718
15719 if (need_invalidate_channel_full) {
15720 invalidate_channel_full(channel_id, !c->is_slow_mode_enabled);
15721 }
15722
15723 bool has_active_group_call = (channel.flags_ & CHANNEL_FLAG_HAS_ACTIVE_GROUP_CALL) != 0;
15724 bool is_group_call_empty = (channel.flags_ & CHANNEL_FLAG_IS_GROUP_CALL_NON_EMPTY) == 0;
15725 td_->messages_manager_->on_update_dialog_group_call(DialogId(channel_id), has_active_group_call, is_group_call_empty,
15726 "receive channel");
15727 }
15728
on_chat_update(telegram_api::channelForbidden & channel,const char * source)15729 void ContactsManager::on_chat_update(telegram_api::channelForbidden &channel, const char *source) {
15730 ChannelId channel_id(channel.id_);
15731 if (!channel_id.is_valid()) {
15732 LOG(ERROR) << "Receive invalid " << channel_id << " from " << source << ": " << to_string(channel);
15733 return;
15734 }
15735
15736 if (channel.flags_ == 0 && channel.access_hash_ == 0 && channel.title_.empty()) {
15737 Channel *c = get_channel_force(channel_id);
15738 LOG(ERROR) << "Receive empty " << to_string(channel) << " from " << source << ", have "
15739 << to_string(get_supergroup_object(channel_id, c));
15740 if (c == nullptr) {
15741 min_channels_.insert(channel_id);
15742 }
15743 return;
15744 }
15745
15746 Channel *c = add_channel(channel_id, "on_channel_forbidden");
15747 if (c->status.is_banned()) { // possibly uninited channel
15748 min_channels_.erase(channel_id);
15749 }
15750 if (c->access_hash != channel.access_hash_) {
15751 c->access_hash = channel.access_hash_;
15752 c->need_save_to_database = true;
15753 }
15754 on_update_channel_title(c, channel_id, std::move(channel.title_));
15755 on_update_channel_photo(c, channel_id, nullptr);
15756 if (c->date != 0) {
15757 c->date = 0;
15758 c->is_changed = true;
15759 }
15760 int32 unban_date = (channel.flags_ & CHANNEL_FLAG_HAS_UNBAN_DATE) != 0 ? channel.until_date_ : 0;
15761 on_update_channel_status(c, channel_id, DialogParticipantStatus::Banned(unban_date));
15762 // on_update_channel_username(c, channel_id, ""); // don't know if channel username is empty, so don't update it
15763 tl_object_ptr<telegram_api::chatBannedRights> banned_rights; // == nullptr
15764 on_update_channel_default_permissions(c, channel_id, get_restricted_rights(std::move(banned_rights)));
15765 // on_update_channel_has_location(c, channel_id, false);
15766 on_update_channel_noforwards(c, channel_id, false);
15767 td_->messages_manager_->on_update_dialog_group_call(DialogId(channel_id), false, false, "receive channelForbidden");
15768
15769 bool sign_messages = false;
15770 bool is_slow_mode_enabled = false;
15771 bool is_megagroup = (channel.flags_ & CHANNEL_FLAG_IS_MEGAGROUP) != 0;
15772 bool is_verified = false;
15773 bool is_scam = false;
15774 bool is_fake = false;
15775
15776 {
15777 bool is_broadcast = (channel.flags_ & CHANNEL_FLAG_IS_BROADCAST) != 0;
15778 LOG_IF(ERROR, is_broadcast == is_megagroup)
15779 << "Receive wrong channel flag is_broadcast == is_megagroup == " << is_megagroup << " from " << source << ": "
15780 << oneline(to_string(channel));
15781 }
15782
15783 if (is_megagroup) {
15784 sign_messages = true;
15785 }
15786
15787 bool need_invalidate_channel_full = false;
15788 if (c->is_slow_mode_enabled != is_slow_mode_enabled || c->is_megagroup != is_megagroup ||
15789 !c->restriction_reasons.empty() || c->is_scam != is_scam || c->is_fake != is_fake) {
15790 // c->has_linked_channel = has_linked_channel;
15791 c->is_slow_mode_enabled = is_slow_mode_enabled;
15792 c->is_megagroup = is_megagroup;
15793 c->restriction_reasons.clear();
15794 c->is_scam = is_scam;
15795 c->is_fake = is_fake;
15796
15797 c->is_changed = true;
15798 need_invalidate_channel_full = true;
15799 }
15800 if (c->sign_messages != sign_messages || c->is_verified != is_verified) {
15801 c->sign_messages = sign_messages;
15802 c->is_verified = is_verified;
15803
15804 c->is_changed = true;
15805 }
15806
15807 bool need_drop_participant_count = c->participant_count != 0;
15808 if (need_drop_participant_count) {
15809 c->participant_count = 0;
15810 c->is_changed = true;
15811 }
15812
15813 if (c->cache_version != Channel::CACHE_VERSION) {
15814 c->cache_version = Channel::CACHE_VERSION;
15815 c->need_save_to_database = true;
15816 }
15817 c->is_received_from_server = true;
15818 update_channel(c, channel_id);
15819
15820 if (need_drop_participant_count) {
15821 auto channel_full = get_channel_full(channel_id, true, "on_chat_update");
15822 if (channel_full != nullptr && channel_full->participant_count != 0) {
15823 channel_full->participant_count = 0;
15824 channel_full->administrator_count = 0;
15825 channel_full->is_changed = true;
15826 update_channel_full(channel_full, channel_id, "on_chat_update 2");
15827 }
15828 }
15829 if (need_invalidate_channel_full) {
15830 invalidate_channel_full(channel_id, !c->is_slow_mode_enabled);
15831 }
15832 }
15833
on_upload_profile_photo(FileId file_id,tl_object_ptr<telegram_api::InputFile> input_file)15834 void ContactsManager::on_upload_profile_photo(FileId file_id, tl_object_ptr<telegram_api::InputFile> input_file) {
15835 auto it = uploaded_profile_photos_.find(file_id);
15836 CHECK(it != uploaded_profile_photos_.end());
15837
15838 double main_frame_timestamp = it->second.main_frame_timestamp;
15839 bool is_animation = it->second.is_animation;
15840 int32 reupload_count = it->second.reupload_count;
15841 auto promise = std::move(it->second.promise);
15842
15843 uploaded_profile_photos_.erase(it);
15844
15845 LOG(INFO) << "Uploaded " << (is_animation ? "animated" : "static") << " profile photo " << file_id
15846 << " with reupload_count = " << reupload_count;
15847 FileView file_view = td_->file_manager_->get_file_view(file_id);
15848 if (file_view.has_remote_location() && input_file == nullptr) {
15849 if (file_view.main_remote_location().is_web()) {
15850 return promise.set_error(Status::Error(400, "Can't use web photo as profile photo"));
15851 }
15852 if (reupload_count == 3) { // upload, ForceReupload repair file reference, reupload
15853 return promise.set_error(Status::Error(400, "Failed to reupload the file"));
15854 }
15855
15856 // delete file reference and forcely reupload the file
15857 if (is_animation) {
15858 CHECK(file_view.get_type() == FileType::Animation);
15859 LOG_CHECK(file_view.main_remote_location().is_common()) << file_view.main_remote_location();
15860 } else {
15861 CHECK(file_view.get_type() == FileType::Photo);
15862 LOG_CHECK(file_view.main_remote_location().is_photo()) << file_view.main_remote_location();
15863 }
15864 auto file_reference =
15865 is_animation ? FileManager::extract_file_reference(file_view.main_remote_location().as_input_document())
15866 : FileManager::extract_file_reference(file_view.main_remote_location().as_input_photo());
15867 td_->file_manager_->delete_file_reference(file_id, file_reference);
15868 upload_profile_photo(file_id, is_animation, main_frame_timestamp, std::move(promise), reupload_count + 1, {-1});
15869 return;
15870 }
15871 CHECK(input_file != nullptr);
15872
15873 td_->create_handler<UploadProfilePhotoQuery>(std::move(promise))
15874 ->send(file_id, std::move(input_file), is_animation, main_frame_timestamp);
15875 }
15876
on_upload_profile_photo_error(FileId file_id,Status status)15877 void ContactsManager::on_upload_profile_photo_error(FileId file_id, Status status) {
15878 LOG(INFO) << "File " << file_id << " has upload error " << status;
15879 CHECK(status.is_error());
15880
15881 auto it = uploaded_profile_photos_.find(file_id);
15882 CHECK(it != uploaded_profile_photos_.end());
15883
15884 auto promise = std::move(it->second.promise);
15885
15886 uploaded_profile_photos_.erase(it);
15887
15888 promise.set_error(std::move(status)); // TODO check that status has valid error code
15889 }
15890
get_user_status_object(UserId user_id,const User * u) const15891 td_api::object_ptr<td_api::UserStatus> ContactsManager::get_user_status_object(UserId user_id, const User *u) const {
15892 if (u->is_bot) {
15893 return make_tl_object<td_api::userStatusOnline>(std::numeric_limits<int32>::max());
15894 }
15895
15896 int32 was_online = get_user_was_online(u, user_id);
15897 switch (was_online) {
15898 case -3:
15899 return make_tl_object<td_api::userStatusLastMonth>();
15900 case -2:
15901 return make_tl_object<td_api::userStatusLastWeek>();
15902 case -1:
15903 return make_tl_object<td_api::userStatusRecently>();
15904 case 0:
15905 return make_tl_object<td_api::userStatusEmpty>();
15906 default: {
15907 int32 time = G()->unix_time();
15908 if (was_online > time) {
15909 return make_tl_object<td_api::userStatusOnline>(was_online);
15910 } else {
15911 return make_tl_object<td_api::userStatusOffline>(was_online);
15912 }
15913 }
15914 }
15915 }
15916
get_update_unknown_user_object(UserId user_id)15917 td_api::object_ptr<td_api::updateUser> ContactsManager::get_update_unknown_user_object(UserId user_id) {
15918 return td_api::make_object<td_api::updateUser>(td_api::make_object<td_api::user>(
15919 user_id.get(), "", "", "", "", td_api::make_object<td_api::userStatusEmpty>(), nullptr, false, false, false,
15920 false, "", false, false, false, td_api::make_object<td_api::userTypeUnknown>(), ""));
15921 }
15922
get_user_id_object(UserId user_id,const char * source) const15923 int64 ContactsManager::get_user_id_object(UserId user_id, const char *source) const {
15924 if (user_id.is_valid() && get_user(user_id) == nullptr && unknown_users_.count(user_id) == 0) {
15925 LOG(ERROR) << "Have no info about " << user_id << " from " << source;
15926 unknown_users_.insert(user_id);
15927 send_closure(G()->td(), &Td::send_update, get_update_unknown_user_object(user_id));
15928 }
15929 return user_id.get();
15930 }
15931
get_user_object(UserId user_id) const15932 tl_object_ptr<td_api::user> ContactsManager::get_user_object(UserId user_id) const {
15933 return get_user_object(user_id, get_user(user_id));
15934 }
15935
get_user_object(UserId user_id,const User * u) const15936 tl_object_ptr<td_api::user> ContactsManager::get_user_object(UserId user_id, const User *u) const {
15937 if (u == nullptr) {
15938 return nullptr;
15939 }
15940 tl_object_ptr<td_api::UserType> type;
15941 if (u->is_deleted) {
15942 type = make_tl_object<td_api::userTypeDeleted>();
15943 } else if (u->is_bot) {
15944 type = make_tl_object<td_api::userTypeBot>(u->can_join_groups, u->can_read_all_group_messages, u->is_inline_bot,
15945 u->inline_query_placeholder, u->need_location_bot);
15946 } else {
15947 type = make_tl_object<td_api::userTypeRegular>();
15948 }
15949
15950 return make_tl_object<td_api::user>(
15951 user_id.get(), u->first_name, u->last_name, u->username, u->phone_number, get_user_status_object(user_id, u),
15952 get_profile_photo_object(td_->file_manager_.get(), u->photo), u->is_contact, u->is_mutual_contact, u->is_verified,
15953 u->is_support, get_restriction_reason_description(u->restriction_reasons), u->is_scam, u->is_fake, u->is_received,
15954 std::move(type), u->language_code);
15955 }
15956
get_user_ids_object(const vector<UserId> & user_ids,const char * source) const15957 vector<int64> ContactsManager::get_user_ids_object(const vector<UserId> &user_ids, const char *source) const {
15958 return transform(user_ids, [this, source](UserId user_id) { return get_user_id_object(user_id, source); });
15959 }
15960
get_users_object(int32 total_count,const vector<UserId> & user_ids) const15961 tl_object_ptr<td_api::users> ContactsManager::get_users_object(int32 total_count,
15962 const vector<UserId> &user_ids) const {
15963 if (total_count == -1) {
15964 total_count = narrow_cast<int32>(user_ids.size());
15965 }
15966 return td_api::make_object<td_api::users>(total_count, get_user_ids_object(user_ids, "get_users_object"));
15967 }
15968
get_user_full_info_object(UserId user_id) const15969 tl_object_ptr<td_api::userFullInfo> ContactsManager::get_user_full_info_object(UserId user_id) const {
15970 return get_user_full_info_object(user_id, get_user_full(user_id));
15971 }
15972
get_user_full_info_object(UserId user_id,const UserFull * user_full) const15973 tl_object_ptr<td_api::userFullInfo> ContactsManager::get_user_full_info_object(UserId user_id,
15974 const UserFull *user_full) const {
15975 CHECK(user_full != nullptr);
15976 bool is_bot = is_user_bot(user_id);
15977 auto commands = transform(user_full->commands, [](const auto &command) { return command.get_bot_command_object(); });
15978 return make_tl_object<td_api::userFullInfo>(
15979 get_chat_photo_object(td_->file_manager_.get(), user_full->photo), user_full->is_blocked,
15980 user_full->can_be_called, user_full->supports_video_calls, user_full->has_private_calls,
15981 !user_full->private_forward_name.empty(), user_full->need_phone_number_privacy_exception,
15982 is_bot ? string() : user_full->about, is_bot ? user_full->about : string(),
15983 is_bot ? user_full->description : string(), user_full->common_chat_count, std::move(commands));
15984 }
15985
get_update_unknown_basic_group_object(ChatId chat_id)15986 td_api::object_ptr<td_api::updateBasicGroup> ContactsManager::get_update_unknown_basic_group_object(ChatId chat_id) {
15987 return td_api::make_object<td_api::updateBasicGroup>(td_api::make_object<td_api::basicGroup>(
15988 chat_id.get(), 0, DialogParticipantStatus::Banned(0).get_chat_member_status_object(), true, 0));
15989 }
15990
get_basic_group_id_object(ChatId chat_id,const char * source) const15991 int64 ContactsManager::get_basic_group_id_object(ChatId chat_id, const char *source) const {
15992 if (chat_id.is_valid() && get_chat(chat_id) == nullptr && unknown_chats_.count(chat_id) == 0) {
15993 LOG(ERROR) << "Have no info about " << chat_id << " from " << source;
15994 unknown_chats_.insert(chat_id);
15995 send_closure(G()->td(), &Td::send_update, get_update_unknown_basic_group_object(chat_id));
15996 }
15997 return chat_id.get();
15998 }
15999
get_basic_group_object(ChatId chat_id)16000 tl_object_ptr<td_api::basicGroup> ContactsManager::get_basic_group_object(ChatId chat_id) {
16001 return get_basic_group_object(chat_id, get_chat(chat_id));
16002 }
16003
get_basic_group_object(ChatId chat_id,const Chat * c)16004 tl_object_ptr<td_api::basicGroup> ContactsManager::get_basic_group_object(ChatId chat_id, const Chat *c) {
16005 if (c == nullptr) {
16006 return nullptr;
16007 }
16008 if (c->migrated_to_channel_id.is_valid()) {
16009 get_channel_force(c->migrated_to_channel_id);
16010 }
16011 return get_basic_group_object_const(chat_id, c);
16012 }
16013
get_basic_group_object_const(ChatId chat_id,const Chat * c) const16014 tl_object_ptr<td_api::basicGroup> ContactsManager::get_basic_group_object_const(ChatId chat_id, const Chat *c) const {
16015 return make_tl_object<td_api::basicGroup>(
16016 chat_id.get(), c->participant_count, get_chat_status(c).get_chat_member_status_object(), c->is_active,
16017 get_supergroup_id_object(c->migrated_to_channel_id, "get_basic_group_object"));
16018 }
16019
get_basic_group_full_info_object(ChatId chat_id) const16020 tl_object_ptr<td_api::basicGroupFullInfo> ContactsManager::get_basic_group_full_info_object(ChatId chat_id) const {
16021 return get_basic_group_full_info_object(get_chat_full(chat_id));
16022 }
16023
get_basic_group_full_info_object(const ChatFull * chat_full) const16024 tl_object_ptr<td_api::basicGroupFullInfo> ContactsManager::get_basic_group_full_info_object(
16025 const ChatFull *chat_full) const {
16026 CHECK(chat_full != nullptr);
16027 auto bot_commands = transform(chat_full->bot_commands, [td = td_](const BotCommands &commands) {
16028 return commands.get_bot_commands_object(td);
16029 });
16030 return make_tl_object<td_api::basicGroupFullInfo>(
16031 get_chat_photo_object(td_->file_manager_.get(), chat_full->photo), chat_full->description,
16032 get_user_id_object(chat_full->creator_user_id, "basicGroupFullInfo"),
16033 transform(chat_full->participants,
16034 [this](const DialogParticipant &chat_participant) { return get_chat_member_object(chat_participant); }),
16035 chat_full->invite_link.get_chat_invite_link_object(this), std::move(bot_commands));
16036 }
16037
get_update_unknown_supergroup_object(ChannelId channel_id)16038 td_api::object_ptr<td_api::updateSupergroup> ContactsManager::get_update_unknown_supergroup_object(
16039 ChannelId channel_id) {
16040 return td_api::make_object<td_api::updateSupergroup>(td_api::make_object<td_api::supergroup>(
16041 channel_id.get(), string(), 0, DialogParticipantStatus::Banned(0).get_chat_member_status_object(), 0, false,
16042 false, false, false, true, false, false, string(), false, false));
16043 }
16044
get_supergroup_id_object(ChannelId channel_id,const char * source) const16045 int64 ContactsManager::get_supergroup_id_object(ChannelId channel_id, const char *source) const {
16046 if (channel_id.is_valid() && get_channel(channel_id) == nullptr && unknown_channels_.count(channel_id) == 0) {
16047 LOG(ERROR) << "Have no info about " << channel_id << " received from " << source;
16048 unknown_channels_.insert(channel_id);
16049 send_closure(G()->td(), &Td::send_update, get_update_unknown_supergroup_object(channel_id));
16050 }
16051 return channel_id.get();
16052 }
16053
get_supergroup_object(ChannelId channel_id) const16054 tl_object_ptr<td_api::supergroup> ContactsManager::get_supergroup_object(ChannelId channel_id) const {
16055 return get_supergroup_object(channel_id, get_channel(channel_id));
16056 }
16057
get_supergroup_object(ChannelId channel_id,const Channel * c)16058 tl_object_ptr<td_api::supergroup> ContactsManager::get_supergroup_object(ChannelId channel_id, const Channel *c) {
16059 if (c == nullptr) {
16060 return nullptr;
16061 }
16062 return td_api::make_object<td_api::supergroup>(
16063 channel_id.get(), c->username, c->date, get_channel_status(c).get_chat_member_status_object(),
16064 c->participant_count, c->has_linked_channel, c->has_location, c->sign_messages, c->is_slow_mode_enabled,
16065 !c->is_megagroup, c->is_gigagroup, c->is_verified, get_restriction_reason_description(c->restriction_reasons),
16066 c->is_scam, c->is_fake);
16067 }
16068
get_supergroup_full_info_object(ChannelId channel_id) const16069 tl_object_ptr<td_api::supergroupFullInfo> ContactsManager::get_supergroup_full_info_object(ChannelId channel_id) const {
16070 return get_supergroup_full_info_object(get_channel_full(channel_id), channel_id);
16071 }
16072
get_supergroup_full_info_object(const ChannelFull * channel_full,ChannelId channel_id) const16073 tl_object_ptr<td_api::supergroupFullInfo> ContactsManager::get_supergroup_full_info_object(
16074 const ChannelFull *channel_full, ChannelId channel_id) const {
16075 CHECK(channel_full != nullptr);
16076 double slow_mode_delay_expires_in = 0;
16077 if (channel_full->slow_mode_next_send_date != 0) {
16078 slow_mode_delay_expires_in = max(channel_full->slow_mode_next_send_date - G()->server_time(), 1e-3);
16079 }
16080 auto bot_commands = transform(channel_full->bot_commands, [td = td_](const BotCommands &commands) {
16081 return commands.get_bot_commands_object(td);
16082 });
16083 return td_api::make_object<td_api::supergroupFullInfo>(
16084 get_chat_photo_object(td_->file_manager_.get(), channel_full->photo), channel_full->description,
16085 channel_full->participant_count, channel_full->administrator_count, channel_full->restricted_count,
16086 channel_full->banned_count, DialogId(channel_full->linked_channel_id).get(), channel_full->slow_mode_delay,
16087 slow_mode_delay_expires_in, channel_full->can_get_participants, channel_full->can_set_username,
16088 channel_full->can_set_sticker_set, channel_full->can_set_location, channel_full->can_view_statistics,
16089 channel_full->is_all_history_available, channel_full->sticker_set_id.get(),
16090 channel_full->location.get_chat_location_object(), channel_full->invite_link.get_chat_invite_link_object(this),
16091 std::move(bot_commands),
16092 get_basic_group_id_object(channel_full->migrated_from_chat_id, "get_supergroup_full_info_object"),
16093 channel_full->migrated_from_max_message_id.get());
16094 }
16095
get_secret_chat_state_object(SecretChatState state)16096 tl_object_ptr<td_api::SecretChatState> ContactsManager::get_secret_chat_state_object(SecretChatState state) {
16097 switch (state) {
16098 case SecretChatState::Waiting:
16099 return make_tl_object<td_api::secretChatStatePending>();
16100 case SecretChatState::Active:
16101 return make_tl_object<td_api::secretChatStateReady>();
16102 case SecretChatState::Closed:
16103 case SecretChatState::Unknown:
16104 return make_tl_object<td_api::secretChatStateClosed>();
16105 default:
16106 UNREACHABLE();
16107 return nullptr;
16108 }
16109 }
16110
get_update_unknown_secret_chat_object(SecretChatId secret_chat_id)16111 td_api::object_ptr<td_api::updateSecretChat> ContactsManager::get_update_unknown_secret_chat_object(
16112 SecretChatId secret_chat_id) {
16113 return td_api::make_object<td_api::updateSecretChat>(td_api::make_object<td_api::secretChat>(
16114 secret_chat_id.get(), 0, get_secret_chat_state_object(SecretChatState::Unknown), false, string(), 0));
16115 }
16116
get_secret_chat_id_object(SecretChatId secret_chat_id,const char * source) const16117 int32 ContactsManager::get_secret_chat_id_object(SecretChatId secret_chat_id, const char *source) const {
16118 if (secret_chat_id.is_valid() && get_secret_chat(secret_chat_id) == nullptr &&
16119 unknown_secret_chats_.count(secret_chat_id) == 0) {
16120 LOG(ERROR) << "Have no info about " << secret_chat_id << " from " << source;
16121 unknown_secret_chats_.insert(secret_chat_id);
16122 send_closure(G()->td(), &Td::send_update, get_update_unknown_secret_chat_object(secret_chat_id));
16123 }
16124 return secret_chat_id.get();
16125 }
16126
get_secret_chat_object(SecretChatId secret_chat_id)16127 tl_object_ptr<td_api::secretChat> ContactsManager::get_secret_chat_object(SecretChatId secret_chat_id) {
16128 return get_secret_chat_object(secret_chat_id, get_secret_chat(secret_chat_id));
16129 }
16130
get_secret_chat_object(SecretChatId secret_chat_id,const SecretChat * secret_chat)16131 tl_object_ptr<td_api::secretChat> ContactsManager::get_secret_chat_object(SecretChatId secret_chat_id,
16132 const SecretChat *secret_chat) {
16133 if (secret_chat == nullptr) {
16134 return nullptr;
16135 }
16136 get_user_force(secret_chat->user_id);
16137 return get_secret_chat_object_const(secret_chat_id, secret_chat);
16138 }
16139
get_secret_chat_object_const(SecretChatId secret_chat_id,const SecretChat * secret_chat) const16140 tl_object_ptr<td_api::secretChat> ContactsManager::get_secret_chat_object_const(SecretChatId secret_chat_id,
16141 const SecretChat *secret_chat) const {
16142 return td_api::make_object<td_api::secretChat>(secret_chat_id.get(),
16143 get_user_id_object(secret_chat->user_id, "secretChat"),
16144 get_secret_chat_state_object(secret_chat->state),
16145 secret_chat->is_outbound, secret_chat->key_hash, secret_chat->layer);
16146 }
16147
get_chat_invite_link_info_object(const string & invite_link)16148 tl_object_ptr<td_api::chatInviteLinkInfo> ContactsManager::get_chat_invite_link_info_object(const string &invite_link) {
16149 auto it = invite_link_infos_.find(invite_link);
16150 if (it == invite_link_infos_.end()) {
16151 return nullptr;
16152 }
16153
16154 auto invite_link_info = it->second.get();
16155 CHECK(invite_link_info != nullptr);
16156
16157 DialogId dialog_id = invite_link_info->dialog_id;
16158 string title;
16159 const DialogPhoto *photo = nullptr;
16160 DialogPhoto invite_link_photo;
16161 string description;
16162 int32 participant_count = 0;
16163 vector<int64> member_user_ids;
16164 bool creates_join_request = false;
16165 bool is_public = false;
16166 bool is_member = false;
16167 td_api::object_ptr<td_api::ChatType> chat_type;
16168
16169 if (dialog_id.is_valid()) {
16170 switch (dialog_id.get_type()) {
16171 case DialogType::Chat: {
16172 auto chat_id = dialog_id.get_chat_id();
16173 const Chat *c = get_chat(chat_id);
16174
16175 if (c != nullptr) {
16176 title = c->title;
16177 photo = &c->photo;
16178 participant_count = c->participant_count;
16179 is_member = c->status.is_member();
16180 } else {
16181 LOG(ERROR) << "Have no information about " << chat_id;
16182 }
16183 chat_type = td_api::make_object<td_api::chatTypeBasicGroup>(
16184 get_basic_group_id_object(chat_id, "get_chat_invite_link_info_object"));
16185 break;
16186 }
16187 case DialogType::Channel: {
16188 auto channel_id = dialog_id.get_channel_id();
16189 const Channel *c = get_channel(channel_id);
16190
16191 bool is_megagroup = false;
16192 if (c != nullptr) {
16193 title = c->title;
16194 photo = &c->photo;
16195 is_public = is_channel_public(c);
16196 is_megagroup = c->is_megagroup;
16197 participant_count = c->participant_count;
16198 is_member = c->status.is_member();
16199 } else {
16200 LOG(ERROR) << "Have no information about " << channel_id;
16201 }
16202 chat_type = td_api::make_object<td_api::chatTypeSupergroup>(
16203 get_supergroup_id_object(channel_id, "get_chat_invite_link_info_object"), !is_megagroup);
16204 break;
16205 }
16206 default:
16207 UNREACHABLE();
16208 }
16209 description = get_dialog_about(dialog_id);
16210 } else {
16211 title = invite_link_info->title;
16212 invite_link_photo = as_fake_dialog_photo(invite_link_info->photo, dialog_id);
16213 photo = &invite_link_photo;
16214 description = invite_link_info->description;
16215 participant_count = invite_link_info->participant_count;
16216 member_user_ids = get_user_ids_object(invite_link_info->participant_user_ids, "get_chat_invite_link_info_object");
16217 creates_join_request = invite_link_info->creates_join_request;
16218 is_public = invite_link_info->is_public;
16219
16220 if (invite_link_info->is_chat) {
16221 chat_type = td_api::make_object<td_api::chatTypeBasicGroup>(0);
16222 } else {
16223 chat_type = td_api::make_object<td_api::chatTypeSupergroup>(0, !invite_link_info->is_megagroup);
16224 }
16225 }
16226
16227 if (dialog_id.is_valid()) {
16228 td_->messages_manager_->force_create_dialog(dialog_id, "get_chat_invite_link_info_object");
16229 }
16230 int32 accessible_for = 0;
16231 if (dialog_id.is_valid() && !is_member) {
16232 auto access_it = dialog_access_by_invite_link_.find(dialog_id);
16233 if (access_it != dialog_access_by_invite_link_.end()) {
16234 accessible_for = td::max(1, access_it->second.accessible_before - G()->unix_time() - 1);
16235 }
16236 }
16237
16238 return make_tl_object<td_api::chatInviteLinkInfo>(dialog_id.get(), accessible_for, std::move(chat_type), title,
16239 get_chat_photo_info_object(td_->file_manager_.get(), photo),
16240 description, participant_count, std::move(member_user_ids),
16241 creates_join_request, is_public);
16242 }
16243
get_support_user(Promise<Unit> && promise)16244 UserId ContactsManager::get_support_user(Promise<Unit> &&promise) {
16245 if (support_user_id_.is_valid()) {
16246 promise.set_value(Unit());
16247 return support_user_id_;
16248 }
16249
16250 td_->create_handler<GetSupportUserQuery>(std::move(promise))->send();
16251 return UserId();
16252 }
16253
after_get_difference()16254 void ContactsManager::after_get_difference() {
16255 if (td_->auth_manager_->is_bot()) {
16256 return;
16257 }
16258 get_user(get_my_id(), 3, Promise<Unit>());
16259
16260 if (td_->is_online()) {
16261 reload_created_public_dialogs(PublicDialogType::HasUsername, Promise<td_api::object_ptr<td_api::chats>>());
16262 reload_created_public_dialogs(PublicDialogType::IsLocationBased, Promise<td_api::object_ptr<td_api::chats>>());
16263 }
16264 }
16265
get_current_state(vector<td_api::object_ptr<td_api::Update>> & updates) const16266 void ContactsManager::get_current_state(vector<td_api::object_ptr<td_api::Update>> &updates) const {
16267 for (auto user_id : unknown_users_) {
16268 if (!have_min_user(user_id)) {
16269 updates.push_back(get_update_unknown_user_object(user_id));
16270 }
16271 }
16272 for (auto chat_id : unknown_chats_) {
16273 if (!have_chat(chat_id)) {
16274 updates.push_back(get_update_unknown_basic_group_object(chat_id));
16275 }
16276 }
16277 for (auto channel_id : unknown_channels_) {
16278 if (!have_channel(channel_id)) {
16279 updates.push_back(get_update_unknown_supergroup_object(channel_id));
16280 }
16281 }
16282 for (auto secret_chat_id : unknown_secret_chats_) {
16283 if (!have_secret_chat(secret_chat_id)) {
16284 updates.push_back(get_update_unknown_secret_chat_object(secret_chat_id));
16285 }
16286 }
16287
16288 for (auto &it : users_) {
16289 updates.push_back(td_api::make_object<td_api::updateUser>(get_user_object(it.first, it.second.get())));
16290 }
16291 for (auto &it : channels_) {
16292 updates.push_back(td_api::make_object<td_api::updateSupergroup>(get_supergroup_object(it.first, it.second.get())));
16293 }
16294 for (auto &it : chats_) { // chat object can contain channel_id, so it must be sent after channels
16295 updates.push_back(
16296 td_api::make_object<td_api::updateBasicGroup>(get_basic_group_object_const(it.first, it.second.get())));
16297 }
16298 for (auto &it : secret_chats_) { // secret chat object contains user_id, so it must be sent after users
16299 updates.push_back(
16300 td_api::make_object<td_api::updateSecretChat>(get_secret_chat_object_const(it.first, it.second.get())));
16301 }
16302
16303 for (auto &it : users_full_) {
16304 updates.push_back(td_api::make_object<td_api::updateUserFullInfo>(
16305 it.first.get(), get_user_full_info_object(it.first, it.second.get())));
16306 }
16307 for (auto &it : channels_full_) {
16308 updates.push_back(td_api::make_object<td_api::updateSupergroupFullInfo>(
16309 it.first.get(), get_supergroup_full_info_object(it.second.get(), it.first)));
16310 }
16311 for (auto &it : chats_full_) {
16312 updates.push_back(td_api::make_object<td_api::updateBasicGroupFullInfo>(
16313 it.first.get(), get_basic_group_full_info_object(it.second.get())));
16314 }
16315 }
16316
16317 } // namespace td
16318