1 /*
2 This file is part of Telegram Desktop,
3 the official desktop application for the Telegram messaging service.
4 
5 For license and copyright information please follow this link:
6 https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
7 */
8 #include "mtproto/mtproto_config.h"
9 
10 #include "storage/serialize_common.h"
11 #include "mtproto/type_utils.h"
12 #include "logs.h"
13 
14 namespace MTP {
15 namespace {
16 
17 constexpr auto kVersion = 1;
18 
19 }
Config(Environment environment)20 Config::Config(Environment environment) : _dcOptions(environment) {
21 	_fields.webFileDcId = _dcOptions.isTestMode() ? 2 : 4;
22 	_fields.txtDomainString = _dcOptions.isTestMode()
23 		? u"tapv3.stel.com"_q
24 		: u"apv3.stel.com"_q;
25 }
26 
Config(const Config & other)27 Config::Config(const Config &other)
28 : _dcOptions(other.dcOptions())
29 , _fields(other._fields) {
30 }
31 
serialize() const32 QByteArray Config::serialize() const {
33 	auto options = _dcOptions.serialize();
34 	auto size = sizeof(qint32) * 2; // version + environment
35 	size += Serialize::bytearraySize(options);
36 	size += 28 * sizeof(qint32);
37 	size += Serialize::stringSize(_fields.internalLinksDomain);
38 	size += Serialize::stringSize(_fields.txtDomainString);
39 
40 	auto result = QByteArray();
41 	result.reserve(size);
42 	{
43 		QDataStream stream(&result, QIODevice::WriteOnly);
44 		stream.setVersion(QDataStream::Qt_5_1);
45 		stream
46 			<< qint32(kVersion)
47 			<< qint32(_dcOptions.isTestMode()
48 				? Environment::Test
49 				: Environment::Production)
50 			<< options
51 			<< qint32(_fields.chatSizeMax)
52 			<< qint32(_fields.megagroupSizeMax)
53 			<< qint32(_fields.forwardedCountMax)
54 			<< qint32(_fields.onlineUpdatePeriod)
55 			<< qint32(_fields.offlineBlurTimeout)
56 			<< qint32(_fields.offlineIdleTimeout)
57 			<< qint32(_fields.onlineFocusTimeout)
58 			<< qint32(_fields.onlineCloudTimeout)
59 			<< qint32(_fields.notifyCloudDelay)
60 			<< qint32(_fields.notifyDefaultDelay)
61 			<< qint32(_fields.savedGifsLimit)
62 			<< qint32(_fields.editTimeLimit)
63 			<< qint32(_fields.revokeTimeLimit)
64 			<< qint32(_fields.revokePrivateTimeLimit)
65 			<< qint32(_fields.revokePrivateInbox ? 1 : 0)
66 			<< qint32(_fields.stickersRecentLimit)
67 			<< qint32(_fields.stickersFavedLimit)
68 			<< qint32(_fields.pinnedDialogsCountMax.current())
69 			<< qint32(_fields.pinnedDialogsInFolderMax.current())
70 			<< _fields.internalLinksDomain
71 			<< qint32(_fields.channelsReadMediaPeriod)
72 			<< qint32(_fields.callReceiveTimeoutMs)
73 			<< qint32(_fields.callRingTimeoutMs)
74 			<< qint32(_fields.callConnectTimeoutMs)
75 			<< qint32(_fields.callPacketTimeoutMs)
76 			<< qint32(_fields.webFileDcId)
77 			<< _fields.txtDomainString
78 			<< qint32(_fields.phoneCallsEnabled.current() ? 1 : 0)
79 			<< qint32(_fields.blockedMode ? 1 : 0)
80 			<< qint32(_fields.captionLengthMax);
81 	}
82 	return result;
83 }
84 
FromSerialized(const QByteArray & serialized)85 std::unique_ptr<Config> Config::FromSerialized(const QByteArray &serialized) {
86 	auto result = std::unique_ptr<Config>();
87 	auto raw = result.get();
88 
89 	QDataStream stream(serialized);
90 	stream.setVersion(QDataStream::Qt_5_1);
91 
92 	auto version = qint32();
93 	stream >> version;
94 	if (version != kVersion) {
95 		return result;
96 	}
97 	auto environment = qint32();
98 	stream >> environment;
99 	switch (environment) {
100 	case qint32(Environment::Test):
101 		result = std::make_unique<Config>(Environment::Test);
102 		break;
103 	case qint32(Environment::Production):
104 		result = std::make_unique<Config>(Environment::Production);
105 		break;
106 	}
107 	if (!(raw = result.get())) {
108 		return result;
109 	}
110 
111 	auto dcOptionsSerialized = QByteArray();
112 	const auto read = [&](auto &field) {
113 		using Type = std::remove_reference_t<decltype(field)>;
114 		if constexpr (std::is_same_v<Type, int>
115 			|| std::is_same_v<Type, rpl::variable<int>>) {
116 			auto value = qint32();
117 			stream >> value;
118 			field = value;
119 		} else if constexpr (std::is_same_v<Type, bool>
120 			|| std::is_same_v<Type, rpl::variable<bool>>) {
121 			auto value = qint32();
122 			stream >> value;
123 			field = (value == 1);
124 		} else if constexpr (std::is_same_v<Type, QByteArray>
125 			|| std::is_same_v<Type, QString>) {
126 			stream >> field;
127 		} else {
128 			static_assert(false_(field), "Bad read() call.");
129 		}
130 	};
131 
132 	read(dcOptionsSerialized);
133 	read(raw->_fields.chatSizeMax);
134 	read(raw->_fields.megagroupSizeMax);
135 	read(raw->_fields.forwardedCountMax);
136 	read(raw->_fields.onlineUpdatePeriod);
137 	read(raw->_fields.offlineBlurTimeout);
138 	read(raw->_fields.offlineIdleTimeout);
139 	read(raw->_fields.onlineFocusTimeout);
140 	read(raw->_fields.onlineCloudTimeout);
141 	read(raw->_fields.notifyCloudDelay);
142 	read(raw->_fields.notifyDefaultDelay);
143 	read(raw->_fields.savedGifsLimit);
144 	read(raw->_fields.editTimeLimit);
145 	read(raw->_fields.revokeTimeLimit);
146 	read(raw->_fields.revokePrivateTimeLimit);
147 	read(raw->_fields.revokePrivateInbox);
148 	read(raw->_fields.stickersRecentLimit);
149 	read(raw->_fields.stickersFavedLimit);
150 	read(raw->_fields.pinnedDialogsCountMax);
151 	read(raw->_fields.pinnedDialogsInFolderMax);
152 	read(raw->_fields.internalLinksDomain);
153 	read(raw->_fields.channelsReadMediaPeriod);
154 	read(raw->_fields.callReceiveTimeoutMs);
155 	read(raw->_fields.callRingTimeoutMs);
156 	read(raw->_fields.callConnectTimeoutMs);
157 	read(raw->_fields.callPacketTimeoutMs);
158 	read(raw->_fields.webFileDcId);
159 	read(raw->_fields.txtDomainString);
160 	read(raw->_fields.phoneCallsEnabled);
161 	read(raw->_fields.blockedMode);
162 	read(raw->_fields.captionLengthMax);
163 
164 	if (stream.status() != QDataStream::Ok
165 		|| !raw->_dcOptions.constructFromSerialized(dcOptionsSerialized)) {
166 		return nullptr;
167 	}
168 	return result;
169 }
170 
values() const171 const ConfigFields &Config::values() const {
172 	return _fields;
173 }
174 
apply(const MTPDconfig & data)175 void Config::apply(const MTPDconfig &data) {
176 	if (mtpIsTrue(data.vtest_mode()) != _dcOptions.isTestMode()) {
177 		LOG(("MTP Error: config with wrong test mode field received!"));
178 		return;
179 	}
180 
181 	DEBUG_LOG(("MTP Info: got config, "
182 		"chat_size_max: %1, "
183 		"date: %2, "
184 		"test_mode: %3, "
185 		"this_dc: %4, "
186 		"dc_options.length: %5"
187 		).arg(data.vchat_size_max().v
188 		).arg(data.vdate().v
189 		).arg(mtpIsTrue(data.vtest_mode())
190 		).arg(data.vthis_dc().v
191 		).arg(data.vdc_options().v.size()));
192 
193 	_fields.chatSizeMax = data.vchat_size_max().v;
194 	_fields.megagroupSizeMax = data.vmegagroup_size_max().v;
195 	_fields.forwardedCountMax = data.vforwarded_count_max().v;
196 	_fields.onlineUpdatePeriod = data.vonline_update_period_ms().v;
197 	_fields.offlineBlurTimeout = data.voffline_blur_timeout_ms().v;
198 	_fields.offlineIdleTimeout = data.voffline_idle_timeout_ms().v;
199 	_fields.onlineCloudTimeout = data.vonline_cloud_timeout_ms().v;
200 	_fields.notifyCloudDelay = data.vnotify_cloud_delay_ms().v;
201 	_fields.notifyDefaultDelay = data.vnotify_default_delay_ms().v;
202 	_fields.savedGifsLimit = data.vsaved_gifs_limit().v;
203 	_fields.editTimeLimit = data.vedit_time_limit().v;
204 	_fields.revokeTimeLimit = data.vrevoke_time_limit().v;
205 	_fields.revokePrivateTimeLimit = data.vrevoke_pm_time_limit().v;
206 	_fields.revokePrivateInbox = data.is_revoke_pm_inbox();
207 	_fields.stickersRecentLimit = data.vstickers_recent_limit().v;
208 	_fields.stickersFavedLimit = data.vstickers_faved_limit().v;
209 	_fields.pinnedDialogsCountMax =
210 		std::max(data.vpinned_dialogs_count_max().v, 1);
211 	_fields.pinnedDialogsInFolderMax =
212 		std::max(data.vpinned_infolder_count_max().v, 1);
213 	_fields.internalLinksDomain = qs(data.vme_url_prefix());
214 	_fields.channelsReadMediaPeriod = data.vchannels_read_media_period().v;
215 	_fields.webFileDcId = data.vwebfile_dc_id().v;
216 	_fields.callReceiveTimeoutMs = data.vcall_receive_timeout_ms().v;
217 	_fields.callRingTimeoutMs = data.vcall_ring_timeout_ms().v;
218 	_fields.callConnectTimeoutMs = data.vcall_connect_timeout_ms().v;
219 	_fields.callPacketTimeoutMs = data.vcall_packet_timeout_ms().v;
220 	_fields.phoneCallsEnabled = data.is_phonecalls_enabled();
221 	_fields.blockedMode = data.is_blocked_mode();
222 	_fields.captionLengthMax = data.vcaption_length_max().v;
223 
224 	if (data.vdc_options().v.empty()) {
225 		LOG(("MTP Error: config with empty dc_options received!"));
226 	} else {
227 		dcOptions().setFromList(data.vdc_options());
228 	}
229 
230 	_updates.fire({});
231 }
232 
updates() const233 rpl::producer<> Config::updates() const {
234 	return _updates.events();
235 }
236 
setChatSizeMax(int value)237 void Config::setChatSizeMax(int value) {
238 	_fields.chatSizeMax = value;
239 }
240 
setSavedGifsLimit(int value)241 void Config::setSavedGifsLimit(int value) {
242 	_fields.savedGifsLimit = value;
243 }
244 
setStickersRecentLimit(int value)245 void Config::setStickersRecentLimit(int value) {
246 	_fields.stickersRecentLimit = value;
247 }
248 
setStickersFavedLimit(int value)249 void Config::setStickersFavedLimit(int value) {
250 	_fields.stickersFavedLimit = value;
251 }
252 
setMegagroupSizeMax(int value)253 void Config::setMegagroupSizeMax(int value) {
254 	_fields.megagroupSizeMax = value;
255 }
256 
setTxtDomainString(const QString & value)257 void Config::setTxtDomainString(const QString &value) {
258 	_fields.txtDomainString = value;
259 }
260 
261 } // namespace MTP
262