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