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/NotificationSettings.h"
8 
9 #include "td/telegram/Global.h"
10 #include "td/telegram/misc.h"
11 
12 #include "td/utils/common.h"
13 
14 #include <limits>
15 
16 namespace td {
17 
operator <<(StringBuilder & string_builder,const DialogNotificationSettings & notification_settings)18 StringBuilder &operator<<(StringBuilder &string_builder, const DialogNotificationSettings &notification_settings) {
19   return string_builder << "[" << notification_settings.mute_until << ", " << notification_settings.sound << ", "
20                         << notification_settings.show_preview << ", " << notification_settings.silent_send_message
21                         << ", " << notification_settings.disable_pinned_message_notifications << ", "
22                         << notification_settings.disable_mention_notifications << ", "
23                         << notification_settings.use_default_mute_until << ", "
24                         << notification_settings.use_default_sound << ", "
25                         << notification_settings.use_default_show_preview << ", "
26                         << notification_settings.use_default_disable_pinned_message_notifications << ", "
27                         << notification_settings.use_default_disable_mention_notifications << ", "
28                         << notification_settings.is_synchronized << "]";
29 }
30 
operator <<(StringBuilder & string_builder,NotificationSettingsScope scope)31 StringBuilder &operator<<(StringBuilder &string_builder, NotificationSettingsScope scope) {
32   switch (scope) {
33     case NotificationSettingsScope::Private:
34       return string_builder << "notification settings for private chats";
35     case NotificationSettingsScope::Group:
36       return string_builder << "notification settings for group chats";
37     case NotificationSettingsScope::Channel:
38       return string_builder << "notification settings for channel chats";
39     default:
40       UNREACHABLE();
41       return string_builder;
42   }
43 }
44 
operator <<(StringBuilder & string_builder,const ScopeNotificationSettings & notification_settings)45 StringBuilder &operator<<(StringBuilder &string_builder, const ScopeNotificationSettings &notification_settings) {
46   return string_builder << "[" << notification_settings.mute_until << ", " << notification_settings.sound << ", "
47                         << notification_settings.show_preview << ", " << notification_settings.is_synchronized << ", "
48                         << notification_settings.disable_pinned_message_notifications << ", "
49                         << notification_settings.disable_mention_notifications << "]";
50 }
51 
get_notification_settings_scope_object(NotificationSettingsScope scope)52 td_api::object_ptr<td_api::NotificationSettingsScope> get_notification_settings_scope_object(
53     NotificationSettingsScope scope) {
54   switch (scope) {
55     case NotificationSettingsScope::Private:
56       return td_api::make_object<td_api::notificationSettingsScopePrivateChats>();
57     case NotificationSettingsScope::Group:
58       return td_api::make_object<td_api::notificationSettingsScopeGroupChats>();
59     case NotificationSettingsScope::Channel:
60       return td_api::make_object<td_api::notificationSettingsScopeChannelChats>();
61     default:
62       UNREACHABLE();
63       return nullptr;
64   }
65 }
66 
get_chat_notification_settings_object(const DialogNotificationSettings * notification_settings)67 td_api::object_ptr<td_api::chatNotificationSettings> get_chat_notification_settings_object(
68     const DialogNotificationSettings *notification_settings) {
69   CHECK(notification_settings != nullptr);
70   return td_api::make_object<td_api::chatNotificationSettings>(
71       notification_settings->use_default_mute_until, max(0, notification_settings->mute_until - G()->unix_time()),
72       notification_settings->use_default_sound, notification_settings->sound,
73       notification_settings->use_default_show_preview, notification_settings->show_preview,
74       notification_settings->use_default_disable_pinned_message_notifications,
75       notification_settings->disable_pinned_message_notifications,
76       notification_settings->use_default_disable_mention_notifications,
77       notification_settings->disable_mention_notifications);
78 }
79 
get_scope_notification_settings_object(const ScopeNotificationSettings * notification_settings)80 td_api::object_ptr<td_api::scopeNotificationSettings> get_scope_notification_settings_object(
81     const ScopeNotificationSettings *notification_settings) {
82   CHECK(notification_settings != nullptr);
83   return td_api::make_object<td_api::scopeNotificationSettings>(
84       max(0, notification_settings->mute_until - G()->unix_time()), notification_settings->sound,
85       notification_settings->show_preview, notification_settings->disable_pinned_message_notifications,
86       notification_settings->disable_mention_notifications);
87 }
88 
get_input_notify_peer(NotificationSettingsScope scope)89 telegram_api::object_ptr<telegram_api::InputNotifyPeer> get_input_notify_peer(NotificationSettingsScope scope) {
90   switch (scope) {
91     case NotificationSettingsScope::Private:
92       return telegram_api::make_object<telegram_api::inputNotifyUsers>();
93     case NotificationSettingsScope::Group:
94       return telegram_api::make_object<telegram_api::inputNotifyChats>();
95     case NotificationSettingsScope::Channel:
96       return telegram_api::make_object<telegram_api::inputNotifyBroadcasts>();
97     default:
98       return nullptr;
99   }
100 }
101 
get_notification_settings_scope(const td_api::object_ptr<td_api::NotificationSettingsScope> & scope)102 NotificationSettingsScope get_notification_settings_scope(
103     const td_api::object_ptr<td_api::NotificationSettingsScope> &scope) {
104   CHECK(scope != nullptr);
105   switch (scope->get_id()) {
106     case td_api::notificationSettingsScopePrivateChats::ID:
107       return NotificationSettingsScope::Private;
108     case td_api::notificationSettingsScopeGroupChats::ID:
109       return NotificationSettingsScope::Group;
110     case td_api::notificationSettingsScopeChannelChats::ID:
111       return NotificationSettingsScope::Channel;
112     default:
113       UNREACHABLE();
114       return NotificationSettingsScope::Private;
115   }
116 }
117 
get_mute_until(int32 mute_for)118 static int32 get_mute_until(int32 mute_for) {
119   if (mute_for <= 0) {
120     return 0;
121   }
122 
123   const int32 MAX_PRECISE_MUTE_FOR = 7 * 86400;
124   int32 current_time = G()->unix_time();
125   if (mute_for > MAX_PRECISE_MUTE_FOR || mute_for >= std::numeric_limits<int32>::max() - current_time) {
126     return std::numeric_limits<int32>::max();
127   }
128   return mute_for + current_time;
129 }
130 
get_dialog_notification_settings(td_api::object_ptr<td_api::chatNotificationSettings> && notification_settings,bool old_silent_send_message)131 Result<DialogNotificationSettings> get_dialog_notification_settings(
132     td_api::object_ptr<td_api::chatNotificationSettings> &&notification_settings, bool old_silent_send_message) {
133   if (notification_settings == nullptr) {
134     return Status::Error(400, "New notification settings must be non-empty");
135   }
136   if (!clean_input_string(notification_settings->sound_)) {
137     return Status::Error(400, "Notification settings sound must be encoded in UTF-8");
138   }
139   if (notification_settings->sound_.empty()) {
140     notification_settings->sound_ = "default";
141   }
142 
143   int32 mute_until =
144       notification_settings->use_default_mute_for_ ? 0 : get_mute_until(notification_settings->mute_for_);
145   return DialogNotificationSettings(notification_settings->use_default_mute_for_, mute_until,
146                                     notification_settings->use_default_sound_, std::move(notification_settings->sound_),
147                                     notification_settings->use_default_show_preview_,
148                                     notification_settings->show_preview_, old_silent_send_message,
149                                     notification_settings->use_default_disable_pinned_message_notifications_,
150                                     notification_settings->disable_pinned_message_notifications_,
151                                     notification_settings->use_default_disable_mention_notifications_,
152                                     notification_settings->disable_mention_notifications_);
153 }
154 
get_scope_notification_settings(td_api::object_ptr<td_api::scopeNotificationSettings> && notification_settings)155 Result<ScopeNotificationSettings> get_scope_notification_settings(
156     td_api::object_ptr<td_api::scopeNotificationSettings> &&notification_settings) {
157   if (notification_settings == nullptr) {
158     return Status::Error(400, "New notification settings must be non-empty");
159   }
160   if (!clean_input_string(notification_settings->sound_)) {
161     return Status::Error(400, "Notification settings sound must be encoded in UTF-8");
162   }
163   if (notification_settings->sound_.empty()) {
164     notification_settings->sound_ = "default";
165   }
166 
167   auto mute_until = get_mute_until(notification_settings->mute_for_);
168   return ScopeNotificationSettings(mute_until, std::move(notification_settings->sound_),
169                                    notification_settings->show_preview_,
170                                    notification_settings->disable_pinned_message_notifications_,
171                                    notification_settings->disable_mention_notifications_);
172 }
173 
get_dialog_notification_settings(tl_object_ptr<telegram_api::peerNotifySettings> && settings,bool old_use_default_disable_pinned_message_notifications,bool old_disable_pinned_message_notifications,bool old_use_default_disable_mention_notifications,bool old_disable_mention_notifications)174 DialogNotificationSettings get_dialog_notification_settings(tl_object_ptr<telegram_api::peerNotifySettings> &&settings,
175                                                             bool old_use_default_disable_pinned_message_notifications,
176                                                             bool old_disable_pinned_message_notifications,
177                                                             bool old_use_default_disable_mention_notifications,
178                                                             bool old_disable_mention_notifications) {
179   bool use_default_mute_until = (settings->flags_ & telegram_api::peerNotifySettings::MUTE_UNTIL_MASK) == 0;
180   bool use_default_sound = (settings->flags_ & telegram_api::peerNotifySettings::SOUND_MASK) == 0;
181   bool use_default_show_preview = (settings->flags_ & telegram_api::peerNotifySettings::SHOW_PREVIEWS_MASK) == 0;
182   auto mute_until = use_default_mute_until || settings->mute_until_ <= G()->unix_time() ? 0 : settings->mute_until_;
183   auto sound = std::move(settings->sound_);
184   if (sound.empty()) {
185     sound = "default";
186   }
187   bool silent_send_message =
188       (settings->flags_ & telegram_api::peerNotifySettings::SILENT_MASK) == 0 ? false : settings->silent_;
189   return {use_default_mute_until,
190           mute_until,
191           use_default_sound,
192           std::move(sound),
193           use_default_show_preview,
194           settings->show_previews_,
195           silent_send_message,
196           old_use_default_disable_pinned_message_notifications,
197           old_disable_pinned_message_notifications,
198           old_use_default_disable_mention_notifications,
199           old_disable_mention_notifications};
200 }
201 
get_scope_notification_settings(tl_object_ptr<telegram_api::peerNotifySettings> && settings,bool old_disable_pinned_message_notifications,bool old_disable_mention_notifications)202 ScopeNotificationSettings get_scope_notification_settings(tl_object_ptr<telegram_api::peerNotifySettings> &&settings,
203                                                           bool old_disable_pinned_message_notifications,
204                                                           bool old_disable_mention_notifications) {
205   auto mute_until = (settings->flags_ & telegram_api::peerNotifySettings::MUTE_UNTIL_MASK) == 0 ||
206                             settings->mute_until_ <= G()->unix_time()
207                         ? 0
208                         : settings->mute_until_;
209   auto sound = std::move(settings->sound_);
210   if (sound.empty()) {
211     sound = "default";
212   }
213   auto show_preview =
214       (settings->flags_ & telegram_api::peerNotifySettings::SHOW_PREVIEWS_MASK) == 0 ? false : settings->show_previews_;
215   return {mute_until, std::move(sound), show_preview, old_disable_pinned_message_notifications,
216           old_disable_mention_notifications};
217 }
218 
are_default_dialog_notification_settings(const DialogNotificationSettings & settings,bool compare_sound)219 bool are_default_dialog_notification_settings(const DialogNotificationSettings &settings, bool compare_sound) {
220   return settings.use_default_mute_until && (!compare_sound || settings.use_default_sound) &&
221          settings.use_default_show_preview && settings.use_default_disable_pinned_message_notifications &&
222          settings.use_default_disable_mention_notifications;
223 }
224 
225 }  // namespace td
226