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/PrivacyManager.h"
8
9 #include "td/telegram/ChannelId.h"
10 #include "td/telegram/ChatId.h"
11 #include "td/telegram/ContactsManager.h"
12 #include "td/telegram/DialogId.h"
13 #include "td/telegram/Global.h"
14 #include "td/telegram/MessagesManager.h"
15 #include "td/telegram/net/NetQueryCreator.h"
16 #include "td/telegram/net/NetQueryDispatcher.h"
17 #include "td/telegram/Td.h"
18
19 #include "td/utils/algorithm.h"
20 #include "td/utils/logging.h"
21
22 #include <algorithm>
23 #include <iterator>
24
25 namespace td {
26
get_user_privacy_setting(tl_object_ptr<td_api::UserPrivacySetting> key)27 Result<PrivacyManager::UserPrivacySetting> PrivacyManager::UserPrivacySetting::get_user_privacy_setting(
28 tl_object_ptr<td_api::UserPrivacySetting> key) {
29 if (key == nullptr) {
30 return Status::Error(400, "UserPrivacySetting must be non-empty");
31 }
32 return UserPrivacySetting(*key);
33 }
34
UserPrivacySetting(const telegram_api::PrivacyKey & key)35 PrivacyManager::UserPrivacySetting::UserPrivacySetting(const telegram_api::PrivacyKey &key) {
36 switch (key.get_id()) {
37 case telegram_api::privacyKeyStatusTimestamp::ID:
38 type_ = Type::UserStatus;
39 break;
40 case telegram_api::privacyKeyChatInvite::ID:
41 type_ = Type::ChatInvite;
42 break;
43 case telegram_api::privacyKeyPhoneCall::ID:
44 type_ = Type::Call;
45 break;
46 case telegram_api::privacyKeyPhoneP2P::ID:
47 type_ = Type::PeerToPeerCall;
48 break;
49 case telegram_api::privacyKeyForwards::ID:
50 type_ = Type::LinkInForwardedMessages;
51 break;
52 case telegram_api::privacyKeyProfilePhoto::ID:
53 type_ = Type::UserProfilePhoto;
54 break;
55 case telegram_api::privacyKeyPhoneNumber::ID:
56 type_ = Type::UserPhoneNumber;
57 break;
58 case telegram_api::privacyKeyAddedByPhone::ID:
59 type_ = Type::FindByPhoneNumber;
60 break;
61 default:
62 UNREACHABLE();
63 type_ = Type::UserStatus;
64 }
65 }
66
get_user_privacy_setting_object() const67 tl_object_ptr<td_api::UserPrivacySetting> PrivacyManager::UserPrivacySetting::get_user_privacy_setting_object() const {
68 switch (type_) {
69 case Type::UserStatus:
70 return make_tl_object<td_api::userPrivacySettingShowStatus>();
71 case Type::ChatInvite:
72 return make_tl_object<td_api::userPrivacySettingAllowChatInvites>();
73 case Type::Call:
74 return make_tl_object<td_api::userPrivacySettingAllowCalls>();
75 case Type::PeerToPeerCall:
76 return make_tl_object<td_api::userPrivacySettingAllowPeerToPeerCalls>();
77 case Type::LinkInForwardedMessages:
78 return make_tl_object<td_api::userPrivacySettingShowLinkInForwardedMessages>();
79 case Type::UserProfilePhoto:
80 return make_tl_object<td_api::userPrivacySettingShowProfilePhoto>();
81 case Type::UserPhoneNumber:
82 return make_tl_object<td_api::userPrivacySettingShowPhoneNumber>();
83 case Type::FindByPhoneNumber:
84 return make_tl_object<td_api::userPrivacySettingAllowFindingByPhoneNumber>();
85 default:
86 UNREACHABLE();
87 return nullptr;
88 }
89 }
get_input_privacy_key() const90 tl_object_ptr<telegram_api::InputPrivacyKey> PrivacyManager::UserPrivacySetting::get_input_privacy_key() const {
91 switch (type_) {
92 case Type::UserStatus:
93 return make_tl_object<telegram_api::inputPrivacyKeyStatusTimestamp>();
94 case Type::ChatInvite:
95 return make_tl_object<telegram_api::inputPrivacyKeyChatInvite>();
96 case Type::Call:
97 return make_tl_object<telegram_api::inputPrivacyKeyPhoneCall>();
98 case Type::PeerToPeerCall:
99 return make_tl_object<telegram_api::inputPrivacyKeyPhoneP2P>();
100 case Type::LinkInForwardedMessages:
101 return make_tl_object<telegram_api::inputPrivacyKeyForwards>();
102 case Type::UserProfilePhoto:
103 return make_tl_object<telegram_api::inputPrivacyKeyProfilePhoto>();
104 case Type::UserPhoneNumber:
105 return make_tl_object<telegram_api::inputPrivacyKeyPhoneNumber>();
106 case Type::FindByPhoneNumber:
107 return make_tl_object<telegram_api::inputPrivacyKeyAddedByPhone>();
108 default:
109 UNREACHABLE();
110 return nullptr;
111 }
112 }
113
UserPrivacySetting(const td_api::UserPrivacySetting & key)114 PrivacyManager::UserPrivacySetting::UserPrivacySetting(const td_api::UserPrivacySetting &key) {
115 switch (key.get_id()) {
116 case td_api::userPrivacySettingShowStatus::ID:
117 type_ = Type::UserStatus;
118 break;
119 case td_api::userPrivacySettingAllowChatInvites::ID:
120 type_ = Type::ChatInvite;
121 break;
122 case td_api::userPrivacySettingAllowCalls::ID:
123 type_ = Type::Call;
124 break;
125 case td_api::userPrivacySettingAllowPeerToPeerCalls::ID:
126 type_ = Type::PeerToPeerCall;
127 break;
128 case td_api::userPrivacySettingShowLinkInForwardedMessages::ID:
129 type_ = Type::LinkInForwardedMessages;
130 break;
131 case td_api::userPrivacySettingShowProfilePhoto::ID:
132 type_ = Type::UserProfilePhoto;
133 break;
134 case td_api::userPrivacySettingShowPhoneNumber::ID:
135 type_ = Type::UserPhoneNumber;
136 break;
137 case td_api::userPrivacySettingAllowFindingByPhoneNumber::ID:
138 type_ = Type::FindByPhoneNumber;
139 break;
140 default:
141 UNREACHABLE();
142 type_ = Type::UserStatus;
143 }
144 }
145
set_chat_ids(const vector<int64> & dialog_ids)146 void PrivacyManager::UserPrivacySettingRule::set_chat_ids(const vector<int64> &dialog_ids) {
147 chat_ids_.clear();
148 auto td = G()->td().get_actor_unsafe();
149 for (auto dialog_id_int : dialog_ids) {
150 DialogId dialog_id(dialog_id_int);
151 if (!td->messages_manager_->have_dialog_force(dialog_id, "UserPrivacySettingRule::set_chat_ids")) {
152 LOG(ERROR) << "Ignore not found " << dialog_id;
153 continue;
154 }
155
156 switch (dialog_id.get_type()) {
157 case DialogType::Chat:
158 chat_ids_.push_back(dialog_id.get_chat_id().get());
159 break;
160 case DialogType::Channel: {
161 auto channel_id = dialog_id.get_channel_id();
162 if (td->contacts_manager_->get_channel_type(channel_id) != ContactsManager::ChannelType::Megagroup) {
163 LOG(ERROR) << "Ignore broadcast " << channel_id;
164 break;
165 }
166 chat_ids_.push_back(channel_id.get());
167 break;
168 }
169 default:
170 LOG(ERROR) << "Ignore " << dialog_id;
171 }
172 }
173 }
174
UserPrivacySettingRule(const td_api::UserPrivacySettingRule & rule)175 PrivacyManager::UserPrivacySettingRule::UserPrivacySettingRule(const td_api::UserPrivacySettingRule &rule) {
176 switch (rule.get_id()) {
177 case td_api::userPrivacySettingRuleAllowContacts::ID:
178 type_ = Type::AllowContacts;
179 break;
180 case td_api::userPrivacySettingRuleAllowAll::ID:
181 type_ = Type::AllowAll;
182 break;
183 case td_api::userPrivacySettingRuleAllowUsers::ID:
184 type_ = Type::AllowUsers;
185 user_ids_ = UserId::get_user_ids(static_cast<const td_api::userPrivacySettingRuleAllowUsers &>(rule).user_ids_);
186 break;
187 case td_api::userPrivacySettingRuleAllowChatMembers::ID:
188 type_ = Type::AllowChatParticipants;
189 set_chat_ids(static_cast<const td_api::userPrivacySettingRuleAllowChatMembers &>(rule).chat_ids_);
190 break;
191 case td_api::userPrivacySettingRuleRestrictContacts::ID:
192 type_ = Type::RestrictContacts;
193 break;
194 case td_api::userPrivacySettingRuleRestrictAll::ID:
195 type_ = Type::RestrictAll;
196 break;
197 case td_api::userPrivacySettingRuleRestrictUsers::ID:
198 type_ = Type::RestrictUsers;
199 user_ids_ =
200 UserId::get_user_ids(static_cast<const td_api::userPrivacySettingRuleRestrictUsers &>(rule).user_ids_);
201 break;
202 case td_api::userPrivacySettingRuleRestrictChatMembers::ID:
203 type_ = Type::RestrictChatParticipants;
204 set_chat_ids(static_cast<const td_api::userPrivacySettingRuleRestrictChatMembers &>(rule).chat_ids_);
205 break;
206 default:
207 UNREACHABLE();
208 }
209 }
210
UserPrivacySettingRule(const telegram_api::PrivacyRule & rule)211 PrivacyManager::UserPrivacySettingRule::UserPrivacySettingRule(const telegram_api::PrivacyRule &rule) {
212 switch (rule.get_id()) {
213 case telegram_api::privacyValueAllowContacts::ID:
214 type_ = Type::AllowContacts;
215 break;
216 case telegram_api::privacyValueAllowAll::ID:
217 type_ = Type::AllowAll;
218 break;
219 case telegram_api::privacyValueAllowUsers::ID:
220 type_ = Type::AllowUsers;
221 user_ids_ = UserId::get_user_ids(static_cast<const telegram_api::privacyValueAllowUsers &>(rule).users_);
222 break;
223 case telegram_api::privacyValueAllowChatParticipants::ID:
224 type_ = Type::AllowChatParticipants;
225 chat_ids_ = static_cast<const telegram_api::privacyValueAllowChatParticipants &>(rule).chats_;
226 break;
227 case telegram_api::privacyValueDisallowContacts::ID:
228 type_ = Type::RestrictContacts;
229 break;
230 case telegram_api::privacyValueDisallowAll::ID:
231 type_ = Type::RestrictAll;
232 break;
233 case telegram_api::privacyValueDisallowUsers::ID:
234 type_ = Type::RestrictUsers;
235 user_ids_ = UserId::get_user_ids(static_cast<const telegram_api::privacyValueDisallowUsers &>(rule).users_);
236 break;
237 case telegram_api::privacyValueDisallowChatParticipants::ID:
238 type_ = Type::RestrictChatParticipants;
239 chat_ids_ = static_cast<const telegram_api::privacyValueDisallowChatParticipants &>(rule).chats_;
240 break;
241 default:
242 UNREACHABLE();
243 }
244 }
245
246 tl_object_ptr<td_api::UserPrivacySettingRule>
get_user_privacy_setting_rule_object() const247 PrivacyManager::UserPrivacySettingRule::get_user_privacy_setting_rule_object() const {
248 switch (type_) {
249 case Type::AllowContacts:
250 return make_tl_object<td_api::userPrivacySettingRuleAllowContacts>();
251 case Type::AllowAll:
252 return make_tl_object<td_api::userPrivacySettingRuleAllowAll>();
253 case Type::AllowUsers:
254 return make_tl_object<td_api::userPrivacySettingRuleAllowUsers>(UserId::get_input_user_ids(user_ids_));
255 case Type::AllowChatParticipants:
256 return make_tl_object<td_api::userPrivacySettingRuleAllowChatMembers>(chat_ids_as_dialog_ids());
257 case Type::RestrictContacts:
258 return make_tl_object<td_api::userPrivacySettingRuleRestrictContacts>();
259 case Type::RestrictAll:
260 return make_tl_object<td_api::userPrivacySettingRuleRestrictAll>();
261 case Type::RestrictUsers:
262 return make_tl_object<td_api::userPrivacySettingRuleRestrictUsers>(UserId::get_input_user_ids(user_ids_));
263 case Type::RestrictChatParticipants:
264 return make_tl_object<td_api::userPrivacySettingRuleRestrictChatMembers>(chat_ids_as_dialog_ids());
265 default:
266 UNREACHABLE();
267 }
268 }
269
get_input_privacy_rule() const270 tl_object_ptr<telegram_api::InputPrivacyRule> PrivacyManager::UserPrivacySettingRule::get_input_privacy_rule() const {
271 switch (type_) {
272 case Type::AllowContacts:
273 return make_tl_object<telegram_api::inputPrivacyValueAllowContacts>();
274 case Type::AllowAll:
275 return make_tl_object<telegram_api::inputPrivacyValueAllowAll>();
276 case Type::AllowUsers:
277 return make_tl_object<telegram_api::inputPrivacyValueAllowUsers>(get_input_users());
278 case Type::AllowChatParticipants:
279 return make_tl_object<telegram_api::inputPrivacyValueAllowChatParticipants>(vector<int64>{chat_ids_});
280 case Type::RestrictContacts:
281 return make_tl_object<telegram_api::inputPrivacyValueDisallowContacts>();
282 case Type::RestrictAll:
283 return make_tl_object<telegram_api::inputPrivacyValueDisallowAll>();
284 case Type::RestrictUsers:
285 return make_tl_object<telegram_api::inputPrivacyValueDisallowUsers>(get_input_users());
286 case Type::RestrictChatParticipants:
287 return make_tl_object<telegram_api::inputPrivacyValueDisallowChatParticipants>(vector<int64>{chat_ids_});
288 default:
289 UNREACHABLE();
290 }
291 }
292
get_user_privacy_setting_rule(tl_object_ptr<telegram_api::PrivacyRule> rule)293 Result<PrivacyManager::UserPrivacySettingRule> PrivacyManager::UserPrivacySettingRule::get_user_privacy_setting_rule(
294 tl_object_ptr<telegram_api::PrivacyRule> rule) {
295 CHECK(rule != nullptr);
296 UserPrivacySettingRule result(*rule);
297 auto td = G()->td().get_actor_unsafe();
298 for (auto user_id : result.user_ids_) {
299 if (!td->contacts_manager_->have_user(user_id)) {
300 return Status::Error(500, "Got inaccessible user from the server");
301 }
302 }
303 for (auto chat_id_int : result.chat_ids_) {
304 ChatId chat_id(chat_id_int);
305 DialogId dialog_id(chat_id);
306 if (!td->contacts_manager_->have_chat(chat_id)) {
307 ChannelId channel_id(chat_id_int);
308 dialog_id = DialogId(channel_id);
309 if (!td->contacts_manager_->have_channel(channel_id)) {
310 return Status::Error(500, "Got inaccessible chat from the server");
311 }
312 }
313 td->messages_manager_->force_create_dialog(dialog_id, "UserPrivacySettingRule");
314 }
315 return result;
316 }
317
get_input_users() const318 vector<tl_object_ptr<telegram_api::InputUser>> PrivacyManager::UserPrivacySettingRule::get_input_users() const {
319 vector<tl_object_ptr<telegram_api::InputUser>> result;
320 for (auto user_id : user_ids_) {
321 auto input_user = G()->td().get_actor_unsafe()->contacts_manager_->get_input_user(user_id);
322 if (input_user != nullptr) {
323 result.push_back(std::move(input_user));
324 } else {
325 LOG(ERROR) << "Have no access to " << user_id;
326 }
327 }
328 return result;
329 }
330
chat_ids_as_dialog_ids() const331 vector<int64> PrivacyManager::UserPrivacySettingRule::chat_ids_as_dialog_ids() const {
332 vector<int64> result;
333 auto td = G()->td().get_actor_unsafe();
334 for (auto chat_id_int : chat_ids_) {
335 ChatId chat_id(chat_id_int);
336 DialogId dialog_id(chat_id);
337 if (!td->contacts_manager_->have_chat(chat_id)) {
338 ChannelId channel_id(chat_id_int);
339 dialog_id = DialogId(channel_id);
340 CHECK(td->contacts_manager_->have_channel(channel_id));
341 }
342 CHECK(td->messages_manager_->have_dialog(dialog_id));
343 result.push_back(dialog_id.get());
344 }
345 return result;
346 }
347
get_restricted_user_ids() const348 vector<UserId> PrivacyManager::UserPrivacySettingRule::get_restricted_user_ids() const {
349 if (type_ == Type::RestrictUsers) {
350 return user_ids_;
351 }
352 return {};
353 }
354
get_user_privacy_setting_rules(tl_object_ptr<telegram_api::account_privacyRules> rules)355 Result<PrivacyManager::UserPrivacySettingRules> PrivacyManager::UserPrivacySettingRules::get_user_privacy_setting_rules(
356 tl_object_ptr<telegram_api::account_privacyRules> rules) {
357 G()->td().get_actor_unsafe()->contacts_manager_->on_get_users(std::move(rules->users_), "on get privacy rules");
358 G()->td().get_actor_unsafe()->contacts_manager_->on_get_chats(std::move(rules->chats_), "on get privacy rules");
359 return get_user_privacy_setting_rules(std::move(rules->rules_));
360 }
361
get_user_privacy_setting_rules(vector<tl_object_ptr<telegram_api::PrivacyRule>> rules)362 Result<PrivacyManager::UserPrivacySettingRules> PrivacyManager::UserPrivacySettingRules::get_user_privacy_setting_rules(
363 vector<tl_object_ptr<telegram_api::PrivacyRule>> rules) {
364 UserPrivacySettingRules result;
365 for (auto &rule : rules) {
366 TRY_RESULT(new_rule, UserPrivacySettingRule::get_user_privacy_setting_rule(std::move(rule)));
367 result.rules_.push_back(new_rule);
368 }
369 if (!result.rules_.empty() && result.rules_.back().get_user_privacy_setting_rule_object()->get_id() ==
370 td_api::userPrivacySettingRuleRestrictAll::ID) {
371 result.rules_.pop_back();
372 }
373 return result;
374 }
375
get_user_privacy_setting_rules(tl_object_ptr<td_api::userPrivacySettingRules> rules)376 Result<PrivacyManager::UserPrivacySettingRules> PrivacyManager::UserPrivacySettingRules::get_user_privacy_setting_rules(
377 tl_object_ptr<td_api::userPrivacySettingRules> rules) {
378 if (rules == nullptr) {
379 return Status::Error(400, "UserPrivacySettingRules must be non-empty");
380 }
381 UserPrivacySettingRules result;
382 for (auto &rule : rules->rules_) {
383 if (rule == nullptr) {
384 return Status::Error(400, "UserPrivacySettingRule must be non-empty");
385 }
386 result.rules_.emplace_back(*rule);
387 }
388 return result;
389 }
390
391 tl_object_ptr<td_api::userPrivacySettingRules>
get_user_privacy_setting_rules_object() const392 PrivacyManager::UserPrivacySettingRules::get_user_privacy_setting_rules_object() const {
393 return make_tl_object<td_api::userPrivacySettingRules>(
394 transform(rules_, [](const auto &rule) { return rule.get_user_privacy_setting_rule_object(); }));
395 }
396
get_input_privacy_rules() const397 vector<tl_object_ptr<telegram_api::InputPrivacyRule>> PrivacyManager::UserPrivacySettingRules::get_input_privacy_rules()
398 const {
399 auto result = transform(rules_, [](const auto &rule) { return rule.get_input_privacy_rule(); });
400 if (!result.empty() && result.back()->get_id() == telegram_api::inputPrivacyValueDisallowAll::ID) {
401 result.pop_back();
402 }
403 return result;
404 }
405
get_restricted_user_ids() const406 vector<UserId> PrivacyManager::UserPrivacySettingRules::get_restricted_user_ids() const {
407 vector<UserId> result;
408 for (auto &rule : rules_) {
409 combine(result, rule.get_restricted_user_ids());
410 }
411 std::sort(result.begin(), result.end(), [](UserId lhs, UserId rhs) { return lhs.get() < rhs.get(); });
412 result.erase(std::unique(result.begin(), result.end()), result.end());
413 return result;
414 }
415
get_privacy(tl_object_ptr<td_api::UserPrivacySetting> key,Promise<tl_object_ptr<td_api::userPrivacySettingRules>> promise)416 void PrivacyManager::get_privacy(tl_object_ptr<td_api::UserPrivacySetting> key,
417 Promise<tl_object_ptr<td_api::userPrivacySettingRules>> promise) {
418 auto r_user_privacy_setting = UserPrivacySetting::get_user_privacy_setting(std::move(key));
419 if (r_user_privacy_setting.is_error()) {
420 return promise.set_error(r_user_privacy_setting.move_as_error());
421 }
422 auto user_privacy_setting = r_user_privacy_setting.move_as_ok();
423 auto &info = get_info(user_privacy_setting);
424 if (info.is_synchronized) {
425 return promise.set_value(info.rules.get_user_privacy_setting_rules_object());
426 }
427 info.get_promises.push_back(std::move(promise));
428 if (info.get_promises.size() > 1u) {
429 // query has already been sent, just wait for the result
430 return;
431 }
432 auto net_query =
433 G()->net_query_creator().create(telegram_api::account_getPrivacy(user_privacy_setting.get_input_privacy_key()));
434
435 send_with_promise(std::move(net_query),
436 PromiseCreator::lambda([this, user_privacy_setting](Result<NetQueryPtr> x_net_query) {
437 on_get_result(user_privacy_setting, [&]() -> Result<UserPrivacySettingRules> {
438 TRY_RESULT(net_query, std::move(x_net_query));
439 TRY_RESULT(rules, fetch_result<telegram_api::account_getPrivacy>(std::move(net_query)));
440 LOG(INFO) << "Receive " << to_string(rules);
441 return UserPrivacySettingRules::get_user_privacy_setting_rules(std::move(rules));
442 }());
443 }));
444 }
445
set_privacy(tl_object_ptr<td_api::UserPrivacySetting> key,tl_object_ptr<td_api::userPrivacySettingRules> rules,Promise<Unit> promise)446 void PrivacyManager::set_privacy(tl_object_ptr<td_api::UserPrivacySetting> key,
447 tl_object_ptr<td_api::userPrivacySettingRules> rules, Promise<Unit> promise) {
448 TRY_RESULT_PROMISE(promise, user_privacy_setting, UserPrivacySetting::get_user_privacy_setting(std::move(key)));
449 TRY_RESULT_PROMISE(promise, privacy_rules, UserPrivacySettingRules::get_user_privacy_setting_rules(std::move(rules)));
450
451 auto &info = get_info(user_privacy_setting);
452 if (info.has_set_query) {
453 // TODO cancel previous query
454 return promise.set_error(Status::Error(400, "Another set_privacy query is active"));
455 }
456 auto net_query = G()->net_query_creator().create(telegram_api::account_setPrivacy(
457 user_privacy_setting.get_input_privacy_key(), privacy_rules.get_input_privacy_rules()));
458
459 info.has_set_query = true;
460 send_with_promise(
461 std::move(net_query), PromiseCreator::lambda([this, user_privacy_setting, promise = std::move(promise)](
462 Result<NetQueryPtr> x_net_query) mutable {
463 promise.set_result([&]() -> Result<Unit> {
464 get_info(user_privacy_setting).has_set_query = false;
465 TRY_RESULT(net_query, std::move(x_net_query));
466 TRY_RESULT(rules, fetch_result<telegram_api::account_setPrivacy>(std::move(net_query)));
467 LOG(INFO) << "Receive " << to_string(rules);
468 TRY_RESULT(privacy_rules, UserPrivacySettingRules::get_user_privacy_setting_rules(std::move(rules)));
469 do_update_privacy(user_privacy_setting, std::move(privacy_rules), true);
470 return Unit();
471 }());
472 }));
473 }
474
update_privacy(tl_object_ptr<telegram_api::updatePrivacy> update)475 void PrivacyManager::update_privacy(tl_object_ptr<telegram_api::updatePrivacy> update) {
476 CHECK(update != nullptr);
477 CHECK(update->key_ != nullptr);
478 UserPrivacySetting user_privacy_setting(*update->key_);
479 auto r_privacy_rules = UserPrivacySettingRules::get_user_privacy_setting_rules(std::move(update->rules_));
480 if (r_privacy_rules.is_error()) {
481 LOG(INFO) << "Skip updatePrivacy: " << r_privacy_rules.error().message();
482 auto &info = get_info(user_privacy_setting);
483 info.is_synchronized = false;
484 } else {
485 do_update_privacy(user_privacy_setting, r_privacy_rules.move_as_ok(), true);
486 }
487 }
488
on_get_result(UserPrivacySetting user_privacy_setting,Result<UserPrivacySettingRules> privacy_rules)489 void PrivacyManager::on_get_result(UserPrivacySetting user_privacy_setting,
490 Result<UserPrivacySettingRules> privacy_rules) {
491 auto &info = get_info(user_privacy_setting);
492 auto promises = std::move(info.get_promises);
493 reset_to_empty(info.get_promises);
494 for (auto &promise : promises) {
495 if (privacy_rules.is_error()) {
496 promise.set_error(privacy_rules.error().clone());
497 } else {
498 promise.set_value(privacy_rules.ok().get_user_privacy_setting_rules_object());
499 }
500 }
501 if (privacy_rules.is_ok()) {
502 do_update_privacy(user_privacy_setting, privacy_rules.move_as_ok(), false);
503 }
504 }
505
do_update_privacy(UserPrivacySetting user_privacy_setting,UserPrivacySettingRules && privacy_rules,bool from_update)506 void PrivacyManager::do_update_privacy(UserPrivacySetting user_privacy_setting, UserPrivacySettingRules &&privacy_rules,
507 bool from_update) {
508 auto &info = get_info(user_privacy_setting);
509 bool was_synchronized = info.is_synchronized;
510 info.is_synchronized = true;
511
512 if (!(info.rules == privacy_rules)) {
513 if ((from_update || was_synchronized) && !G()->close_flag()) {
514 switch (user_privacy_setting.type()) {
515 case UserPrivacySetting::Type::UserStatus: {
516 send_closure_later(G()->contacts_manager(), &ContactsManager::on_update_online_status_privacy);
517
518 auto old_restricted = info.rules.get_restricted_user_ids();
519 auto new_restricted = privacy_rules.get_restricted_user_ids();
520 if (old_restricted != new_restricted) {
521 // if a user was unrestricted, it is not received from the server anymore
522 // we need to reget their online status manually
523 std::vector<UserId> unrestricted;
524 std::set_difference(old_restricted.begin(), old_restricted.end(), new_restricted.begin(),
525 new_restricted.end(), std::back_inserter(unrestricted),
526 [](UserId lhs, UserId rhs) { return lhs.get() < rhs.get(); });
527 for (auto &user_id : unrestricted) {
528 send_closure_later(G()->contacts_manager(), &ContactsManager::reload_user, user_id, Promise<Unit>());
529 }
530 }
531 break;
532 }
533 case UserPrivacySetting::Type::UserPhoneNumber:
534 send_closure_later(G()->contacts_manager(), &ContactsManager::on_update_phone_number_privacy);
535 break;
536 default:
537 break;
538 }
539 }
540
541 info.rules = std::move(privacy_rules);
542 send_closure(
543 G()->td(), &Td::send_update,
544 make_tl_object<td_api::updateUserPrivacySettingRules>(user_privacy_setting.get_user_privacy_setting_object(),
545 info.rules.get_user_privacy_setting_rules_object()));
546 }
547 }
548
on_result(NetQueryPtr query)549 void PrivacyManager::on_result(NetQueryPtr query) {
550 auto token = get_link_token();
551 container_.extract(token).set_value(std::move(query));
552 }
553
send_with_promise(NetQueryPtr query,Promise<NetQueryPtr> promise)554 void PrivacyManager::send_with_promise(NetQueryPtr query, Promise<NetQueryPtr> promise) {
555 auto id = container_.create(std::move(promise));
556 G()->net_query_dispatcher().dispatch_with_callback(std::move(query), actor_shared(this, id));
557 }
558
hangup()559 void PrivacyManager::hangup() {
560 container_.for_each(
561 [](auto id, Promise<NetQueryPtr> &promise) { promise.set_error(Global::request_aborted_error()); });
562 stop();
563 }
564
565 } // namespace td
566