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 "api/api_updates.h"
9 
10 #include "api/api_authorizations.h"
11 #include "api/api_text_entities.h"
12 #include "api/api_user_privacy.h"
13 #include "main/main_session.h"
14 #include "main/main_account.h"
15 #include "mtproto/mtp_instance.h"
16 #include "mtproto/mtproto_config.h"
17 #include "mtproto/mtproto_dc_options.h"
18 #include "data/stickers/data_stickers.h"
19 #include "data/data_session.h"
20 #include "data/data_user.h"
21 #include "data/data_chat.h"
22 #include "data/data_changes.h"
23 #include "data/data_channel.h"
24 #include "data/data_chat_filters.h"
25 #include "data/data_cloud_themes.h"
26 #include "data/data_group_call.h"
27 #include "data/data_drafts.h"
28 #include "data/data_histories.h"
29 #include "data/data_folder.h"
30 #include "data/data_scheduled_messages.h"
31 #include "data/data_send_action.h"
32 #include "chat_helpers/emoji_interactions.h"
33 #include "lang/lang_cloud_manager.h"
34 #include "history/history.h"
35 #include "history/history_item.h"
36 #include "core/application.h"
37 #include "storage/storage_account.h"
38 #include "storage/storage_facade.h"
39 #include "storage/storage_user_photos.h"
40 #include "storage/storage_shared_media.h"
41 #include "calls/calls_instance.h"
42 #include "base/unixtime.h"
43 #include "window/window_session_controller.h"
44 #include "window/window_controller.h"
45 #include "ui/boxes/confirm_box.h"
46 #include "apiwrap.h"
47 #include "ui/text/format_values.h" // Ui::FormatPhone
48 #include "app.h" // App::quitting
49 
50 namespace Api {
51 namespace {
52 
53 constexpr auto kChannelGetDifferenceLimit = 100;
54 
55 // 1s wait after show channel history before sending getChannelDifference.
56 constexpr auto kWaitForChannelGetDifference = crl::time(1000);
57 
58 // If nothing is received in 1 min we ping.
59 constexpr auto kNoUpdatesTimeout = 60 * 1000;
60 
61 // If nothing is received in 1 min when was a sleepmode we ping.
62 constexpr auto kNoUpdatesAfterSleepTimeout = 60 * crl::time(1000);
63 
64 enum class DataIsLoadedResult {
65 	NotLoaded = 0,
66 	FromNotLoaded = 1,
67 	MentionNotLoaded = 2,
68 	Ok = 3,
69 };
70 
ProcessScheduledMessageWithElapsedTime(not_null<Main::Session * > session,bool needToAdd,const MTPDmessage & data)71 void ProcessScheduledMessageWithElapsedTime(
72 		not_null<Main::Session*> session,
73 		bool needToAdd,
74 		const MTPDmessage &data) {
75 	if (needToAdd && !data.is_from_scheduled()) {
76 		// If we still need to add a new message,
77 		// we should first check if this message is in
78 		// the list of scheduled messages.
79 		// This is necessary to correctly update the file reference.
80 		// Note that when a message is scheduled until online
81 		// while the recipient is already online, the server sends
82 		// an ordinary new message with skipped "from_scheduled" flag.
83 		session->data().scheduledMessages().checkEntitiesAndUpdate(data);
84 	}
85 }
86 
IsForceLogoutNotification(const MTPDupdateServiceNotification & data)87 bool IsForceLogoutNotification(const MTPDupdateServiceNotification &data) {
88 	return qs(data.vtype()).startsWith(qstr("AUTH_KEY_DROP_"));
89 }
90 
HasForceLogoutNotification(const MTPUpdates & updates)91 bool HasForceLogoutNotification(const MTPUpdates &updates) {
92 	const auto checkUpdate = [](const MTPUpdate &update) {
93 		if (update.type() != mtpc_updateServiceNotification) {
94 			return false;
95 		}
96 		return IsForceLogoutNotification(
97 			update.c_updateServiceNotification());
98 	};
99 	const auto checkVector = [&](const MTPVector<MTPUpdate> &list) {
100 		for (const auto &update : list.v) {
101 			if (checkUpdate(update)) {
102 				return true;
103 			}
104 		}
105 		return false;
106 	};
107 	switch (updates.type()) {
108 	case mtpc_updates:
109 		return checkVector(updates.c_updates().vupdates());
110 	case mtpc_updatesCombined:
111 		return checkVector(updates.c_updatesCombined().vupdates());
112 	case mtpc_updateShort:
113 		return checkUpdate(updates.c_updateShort().vupdate());
114 	}
115 	return false;
116 }
117 
ForwardedInfoDataLoaded(not_null<Main::Session * > session,const MTPMessageFwdHeader & header)118 bool ForwardedInfoDataLoaded(
119 		not_null<Main::Session*> session,
120 		const MTPMessageFwdHeader &header) {
121 	return header.match([&](const MTPDmessageFwdHeader &data) {
122 		if (const auto fromId = data.vfrom_id()) {
123 			// Fully loaded is required in this case.
124 			if (!session->data().peerLoaded(peerFromMTP(*fromId))) {
125 				return false;
126 			}
127 		}
128 		return true;
129 	});
130 }
131 
MentionUsersLoaded(not_null<Main::Session * > session,const MTPVector<MTPMessageEntity> & entities)132 bool MentionUsersLoaded(
133 		not_null<Main::Session*> session,
134 		const MTPVector<MTPMessageEntity> &entities) {
135 	for (const auto &entity : entities.v) {
136 		auto type = entity.type();
137 		if (type == mtpc_messageEntityMentionName) {
138 			if (!session->data().userLoaded(entity.c_messageEntityMentionName().vuser_id())) {
139 				return false;
140 			}
141 		} else if (type == mtpc_inputMessageEntityMentionName) {
142 			auto &inputUser = entity.c_inputMessageEntityMentionName().vuser_id();
143 			if (inputUser.type() == mtpc_inputUser) {
144 				if (!session->data().userLoaded(inputUser.c_inputUser().vuser_id())) {
145 					return false;
146 				}
147 			}
148 		}
149 	}
150 	return true;
151 }
152 
AllDataLoadedForMessage(not_null<Main::Session * > session,const MTPMessage & message)153 DataIsLoadedResult AllDataLoadedForMessage(
154 		not_null<Main::Session*> session,
155 		const MTPMessage &message) {
156 	return message.match([&](const MTPDmessage &message) {
157 		if (const auto fromId = message.vfrom_id()) {
158 			if (!message.is_post()
159 				&& !session->data().peerLoaded(peerFromMTP(*fromId))) {
160 				return DataIsLoadedResult::FromNotLoaded;
161 			}
162 		}
163 		if (const auto viaBotId = message.vvia_bot_id()) {
164 			if (!session->data().userLoaded(*viaBotId)) {
165 				return DataIsLoadedResult::NotLoaded;
166 			}
167 		}
168 		if (const auto fwd = message.vfwd_from()) {
169 			if (!ForwardedInfoDataLoaded(session, *fwd)) {
170 				return DataIsLoadedResult::NotLoaded;
171 			}
172 		}
173 		if (const auto entities = message.ventities()) {
174 			if (!MentionUsersLoaded(session, *entities)) {
175 				return DataIsLoadedResult::MentionNotLoaded;
176 			}
177 		}
178 		return DataIsLoadedResult::Ok;
179 	}, [&](const MTPDmessageService &message) {
180 		if (const auto fromId = message.vfrom_id()) {
181 			if (!message.is_post()
182 				&& !session->data().peerLoaded(peerFromMTP(*fromId))) {
183 				return DataIsLoadedResult::FromNotLoaded;
184 			}
185 		}
186 		return message.vaction().match(
187 		[&](const MTPDmessageActionChatAddUser &action) {
188 			for (const auto &userId : action.vusers().v) {
189 				if (!session->data().userLoaded(userId)) {
190 					return DataIsLoadedResult::NotLoaded;
191 				}
192 			}
193 			return DataIsLoadedResult::Ok;
194 		}, [&](const MTPDmessageActionChatJoinedByLink &action) {
195 			if (!session->data().userLoaded(action.vinviter_id())) {
196 				return DataIsLoadedResult::NotLoaded;
197 			}
198 			return DataIsLoadedResult::Ok;
199 		}, [&](const MTPDmessageActionChatDeleteUser &action) {
200 			if (!session->data().userLoaded(action.vuser_id())) {
201 				return DataIsLoadedResult::NotLoaded;
202 			}
203 			return DataIsLoadedResult::Ok;
204 		}, [](const auto &) {
205 			return DataIsLoadedResult::Ok;
206 		});
207 	}, [](const MTPDmessageEmpty &message) {
208 		return DataIsLoadedResult::Ok;
209 	});
210 }
211 
212 } // namespace
213 
Updates(not_null<Main::Session * > session)214 Updates::Updates(not_null<Main::Session*> session)
215 : _session(session)
216 , _noUpdatesTimer([=] { sendPing(); })
__anon38509ee60d02null217 , _onlineTimer([=] { updateOnline(); })
218 , _ptsWaiter(this)
__anon38509ee60e02null219 , _byPtsTimer([=] { getDifferenceByPts(); })
__anon38509ee60f02null220 , _bySeqTimer([=] { getDifference(); })
__anon38509ee61002null221 , _byMinChannelTimer([=] { getDifference(); })
__anon38509ee61102null222 , _failDifferenceTimer([=] { getDifferenceAfterFail(); })
__anon38509ee61202null223 , _idleFinishTimer([=] { checkIdleFinish(); }) {
224 	_ptsWaiter.setRequesting(true);
225 
226 	session->account().mtpUpdates(
__anon38509ee61302(const MTPUpdates &updates) 227 	) | rpl::start_with_next([=](const MTPUpdates &updates) {
228 		mtpUpdateReceived(updates);
229 	}, _lifetime);
230 
231 	session->account().mtpNewSessionCreated(
__anon38509ee61402null232 	) | rpl::start_with_next([=] {
233 		mtpNewSessionCreated();
234 	}, _lifetime);
235 
236 	api().request(MTPupdates_GetState(
__anon38509ee61502(const MTPupdates_State &result) 237 	)).done([=](const MTPupdates_State &result) {
238 		stateDone(result);
239 	}).send();
240 
241 	using namespace rpl::mappers;
242 	session->changes().peerUpdates(
243 		Data::PeerUpdate::Flag::FullInfo
__anon38509ee61602(const Data::PeerUpdate &update) 244 	) | rpl::filter([](const Data::PeerUpdate &update) {
245 		return update.peer->isChat() || update.peer->isMegagroup();
246 	}) | rpl::start_with_next([=](const Data::PeerUpdate &update) {
247 		const auto peer = update.peer;
248 		if (const auto list = _pendingSpeakingCallParticipants.take(peer)) {
249 			if (const auto call = peer->groupCall()) {
250 				for (const auto &[participantPeerId, when] : *list) {
251 					call->applyActiveUpdate(
252 						participantPeerId,
253 						Data::LastSpokeTimes{
254 							.anything = when,
255 							.voice = when
256 						},
257 						peer->owner().peerLoaded(participantPeerId));
258 				}
259 			}
260 		}
261 	}, _lifetime);
262 }
263 
session() const264 Main::Session &Updates::session() const {
265 	return *_session;
266 }
267 
api() const268 ApiWrap &Updates::api() const {
269 	return _session->api();
270 }
271 
checkLastUpdate(bool afterSleep)272 void Updates::checkLastUpdate(bool afterSleep) {
273 	const auto now = crl::now();
274 	const auto skip = afterSleep
275 		? kNoUpdatesAfterSleepTimeout
276 		: kNoUpdatesTimeout;
277 	if (_lastUpdateTime && now > _lastUpdateTime + skip) {
278 		_lastUpdateTime = now;
279 		sendPing();
280 	}
281 }
282 
feedUpdateVector(const MTPVector<MTPUpdate> & updates,SkipUpdatePolicy policy)283 void Updates::feedUpdateVector(
284 		const MTPVector<MTPUpdate> &updates,
285 		SkipUpdatePolicy policy) {
286 	auto list = updates.v;
287 	const auto hasGroupCallParticipantUpdates = ranges::contains(
288 		list,
289 		mtpc_updateGroupCallParticipants,
290 		&MTPUpdate::type);
291 	if (hasGroupCallParticipantUpdates) {
292 		ranges::stable_sort(list, std::less<>(), [](const MTPUpdate &entry) {
293 			if (entry.type() == mtpc_updateGroupCallParticipants) {
294 				return 0;
295 			} else {
296 				return 1;
297 			}
298 		});
299 	} else if (policy == SkipUpdatePolicy::SkipExceptGroupCallParticipants) {
300 		return;
301 	}
302 	for (const auto &entry : std::as_const(list)) {
303 		const auto type = entry.type();
304 		if ((policy == SkipUpdatePolicy::SkipMessageIds
305 			&& type == mtpc_updateMessageID)
306 			|| (policy == SkipUpdatePolicy::SkipExceptGroupCallParticipants
307 				&& type != mtpc_updateGroupCallParticipants)) {
308 			continue;
309 		}
310 		feedUpdate(entry);
311 	}
312 	session().data().sendHistoryChangeNotifications();
313 }
314 
feedMessageIds(const MTPVector<MTPUpdate> & updates)315 void Updates::feedMessageIds(const MTPVector<MTPUpdate> &updates) {
316 	for (const auto &update : updates.v) {
317 		if (update.type() == mtpc_updateMessageID) {
318 			feedUpdate(update);
319 		}
320 	}
321 }
322 
setState(int32 pts,int32 date,int32 qts,int32 seq)323 void Updates::setState(int32 pts, int32 date, int32 qts, int32 seq) {
324 	if (pts) {
325 		_ptsWaiter.init(pts);
326 	}
327 	if (_updatesDate < date && !_byMinChannelTimer.isActive()) {
328 		_updatesDate = date;
329 	}
330 	if (qts && _updatesQts < qts) {
331 		_updatesQts = qts;
332 	}
333 	if (seq && seq != _updatesSeq) {
334 		_updatesSeq = seq;
335 		if (_bySeqTimer.isActive()) {
336 			_bySeqTimer.cancel();
337 		}
338 		while (!_bySeqUpdates.empty()) {
339 			const auto s = _bySeqUpdates.front().first;
340 			if (s <= seq + 1) {
341 				const auto v = _bySeqUpdates.front().second;
342 				_bySeqUpdates.erase(_bySeqUpdates.begin());
343 				if (s == seq + 1) {
344 					return applyUpdates(v);
345 				}
346 			} else {
347 				if (!_bySeqTimer.isActive()) {
348 					_bySeqTimer.callOnce(PtsWaiter::kWaitForSkippedTimeout);
349 				}
350 				break;
351 			}
352 		}
353 	}
354 }
355 
channelDifferenceDone(not_null<ChannelData * > channel,const MTPupdates_ChannelDifference & difference)356 void Updates::channelDifferenceDone(
357 		not_null<ChannelData*> channel,
358 		const MTPupdates_ChannelDifference &difference) {
359 	_channelFailDifferenceTimeout.remove(channel);
360 
361 	const auto timeout = difference.match([&](const auto &data) {
362 		return data.vtimeout().value_or_empty();
363 	});
364 	const auto isFinal = difference.match([&](const auto &data) {
365 		return data.is_final();
366 	});
367 	difference.match([&](const MTPDupdates_channelDifferenceEmpty &data) {
368 		channel->ptsInit(data.vpts().v);
369 	}, [&](const MTPDupdates_channelDifferenceTooLong &data) {
370 		session().data().processUsers(data.vusers());
371 		session().data().processChats(data.vchats());
372 		const auto history = session().data().historyLoaded(channel->id);
373 		if (history) {
374 			history->setNotLoadedAtBottom();
375 			requestChannelRangeDifference(history);
376 		}
377 		data.vdialog().match([&](const MTPDdialog &data) {
378 			if (const auto pts = data.vpts()) {
379 				channel->ptsInit(pts->v);
380 			}
381 		}, [&](const MTPDdialogFolder &) {
382 		});
383 		session().data().applyDialogs(
384 			nullptr,
385 			data.vmessages().v,
386 			QVector<MTPDialog>(1, data.vdialog()));
387 		session().data().channelDifferenceTooLong(channel);
388 	}, [&](const MTPDupdates_channelDifference &data) {
389 		feedChannelDifference(data);
390 		channel->ptsInit(data.vpts().v);
391 	});
392 
393 	channel->ptsSetRequesting(false);
394 
395 	if (!isFinal) {
396 		MTP_LOG(0, ("getChannelDifference "
397 			"{ good - after not final channelDifference was received }%1"
398 			).arg(_session->mtp().isTestMode() ? " TESTMODE" : ""));
399 		getChannelDifference(channel);
400 	} else if (ranges::contains(
401 			_activeChats,
402 			channel,
403 			[](const auto &pair) { return pair.second.peer; })) {
404 		channel->ptsWaitingForShortPoll(timeout
405 			? (timeout * crl::time(1000))
406 			: kWaitForChannelGetDifference);
407 	}
408 }
409 
feedChannelDifference(const MTPDupdates_channelDifference & data)410 void Updates::feedChannelDifference(
411 		const MTPDupdates_channelDifference &data) {
412 	session().data().processUsers(data.vusers());
413 	session().data().processChats(data.vchats());
414 
415 	_handlingChannelDifference = true;
416 	feedMessageIds(data.vother_updates());
417 	session().data().processMessages(
418 		data.vnew_messages(),
419 		NewMessageType::Unread);
420 	feedUpdateVector(
421 		data.vother_updates(),
422 		SkipUpdatePolicy::SkipMessageIds);
423 	_handlingChannelDifference = false;
424 }
425 
channelDifferenceFail(not_null<ChannelData * > channel,const MTP::Error & error)426 void Updates::channelDifferenceFail(
427 		not_null<ChannelData*> channel,
428 		const MTP::Error &error) {
429 	LOG(("RPC Error in getChannelDifference: %1 %2: %3").arg(
430 		QString::number(error.code()),
431 		error.type(),
432 		error.description()));
433 	failDifferenceStartTimerFor(channel);
434 }
435 
stateDone(const MTPupdates_State & state)436 void Updates::stateDone(const MTPupdates_State &state) {
437 	const auto &d = state.c_updates_state();
438 	setState(d.vpts().v, d.vdate().v, d.vqts().v, d.vseq().v);
439 
440 	_lastUpdateTime = crl::now();
441 	_noUpdatesTimer.callOnce(kNoUpdatesTimeout);
442 	_ptsWaiter.setRequesting(false);
443 
444 	session().api().requestDialogs();
445 	updateOnline();
446 }
447 
differenceDone(const MTPupdates_Difference & result)448 void Updates::differenceDone(const MTPupdates_Difference &result) {
449 	_failDifferenceTimeout = 1;
450 
451 	switch (result.type()) {
452 	case mtpc_updates_differenceEmpty: {
453 		auto &d = result.c_updates_differenceEmpty();
454 		setState(_ptsWaiter.current(), d.vdate().v, _updatesQts, d.vseq().v);
455 
456 		_lastUpdateTime = crl::now();
457 		_noUpdatesTimer.callOnce(kNoUpdatesTimeout);
458 
459 		_ptsWaiter.setRequesting(false);
460 	} break;
461 	case mtpc_updates_differenceSlice: {
462 		auto &d = result.c_updates_differenceSlice();
463 		feedDifference(d.vusers(), d.vchats(), d.vnew_messages(), d.vother_updates());
464 
465 		auto &s = d.vintermediate_state().c_updates_state();
466 		setState(s.vpts().v, s.vdate().v, s.vqts().v, s.vseq().v);
467 
468 		_ptsWaiter.setRequesting(false);
469 
470 		MTP_LOG(0, ("getDifference "
471 			"{ good - after a slice of difference was received }%1"
472 			).arg(_session->mtp().isTestMode() ? " TESTMODE" : ""));
473 		getDifference();
474 	} break;
475 	case mtpc_updates_difference: {
476 		auto &d = result.c_updates_difference();
477 		feedDifference(d.vusers(), d.vchats(), d.vnew_messages(), d.vother_updates());
478 
479 		stateDone(d.vstate());
480 	} break;
481 	case mtpc_updates_differenceTooLong: {
482 		LOG(("API Error: updates.differenceTooLong is not supported by Telegram Desktop!"));
483 	} break;
484 	};
485 }
486 
whenGetDiffChanged(ChannelData * channel,int32 ms,base::flat_map<not_null<ChannelData * >,crl::time> & whenMap,crl::time & curTime)487 bool Updates::whenGetDiffChanged(
488 		ChannelData *channel,
489 		int32 ms,
490 		base::flat_map<not_null<ChannelData*>, crl::time> &whenMap,
491 		crl::time &curTime) {
492 	if (channel) {
493 		if (ms <= 0) {
494 			const auto i = whenMap.find(channel);
495 			if (i != whenMap.cend()) {
496 				whenMap.erase(i);
497 			} else {
498 				return false;
499 			}
500 		} else {
501 			auto when = crl::now() + ms;
502 			const auto i = whenMap.find(channel);
503 			if (i != whenMap.cend()) {
504 				if (i->second > when) {
505 					i->second = when;
506 				} else {
507 					return false;
508 				}
509 			} else {
510 				whenMap.emplace(channel, when);
511 			}
512 		}
513 	} else {
514 		if (ms <= 0) {
515 			if (curTime) {
516 				curTime = 0;
517 			} else {
518 				return false;
519 			}
520 		} else {
521 			auto when = crl::now() + ms;
522 			if (!curTime || curTime > when) {
523 				curTime = when;
524 			} else {
525 				return false;
526 			}
527 		}
528 	}
529 	return true;
530 }
531 
ptsWaiterStartTimerFor(ChannelData * channel,crl::time ms)532 void Updates::ptsWaiterStartTimerFor(ChannelData *channel, crl::time ms) {
533 	if (whenGetDiffChanged(channel, ms, _whenGetDiffByPts, _getDifferenceTimeByPts)) {
534 		getDifferenceByPts();
535 	}
536 }
537 
failDifferenceStartTimerFor(ChannelData * channel)538 void Updates::failDifferenceStartTimerFor(ChannelData *channel) {
539 	auto &timeout = [&]() -> crl::time & {
540 		if (!channel) {
541 			return _failDifferenceTimeout;
542 		}
543 		const auto i = _channelFailDifferenceTimeout.find(channel);
544 		return (i == _channelFailDifferenceTimeout.end())
545 			? _channelFailDifferenceTimeout.emplace(channel, 1).first->second
546 			: i->second;
547 	}();
548 	if (whenGetDiffChanged(channel, timeout * 1000, _whenGetDiffAfterFail, _getDifferenceTimeAfterFail)) {
549 		getDifferenceAfterFail();
550 	}
551 	if (timeout < 64) timeout *= 2;
552 }
553 
updateAndApply(int32 pts,int32 ptsCount,const MTPUpdates & updates)554 bool Updates::updateAndApply(
555 		int32 pts,
556 		int32 ptsCount,
557 		const MTPUpdates &updates) {
558 	return _ptsWaiter.updateAndApply(nullptr, pts, ptsCount, updates);
559 }
560 
updateAndApply(int32 pts,int32 ptsCount,const MTPUpdate & update)561 bool Updates::updateAndApply(
562 		int32 pts,
563 		int32 ptsCount,
564 		const MTPUpdate &update) {
565 	return _ptsWaiter.updateAndApply(nullptr, pts, ptsCount, update);
566 }
567 
updateAndApply(int32 pts,int32 ptsCount)568 bool Updates::updateAndApply(int32 pts, int32 ptsCount) {
569 	return _ptsWaiter.updateAndApply(nullptr, pts, ptsCount);
570 }
571 
feedDifference(const MTPVector<MTPUser> & users,const MTPVector<MTPChat> & chats,const MTPVector<MTPMessage> & msgs,const MTPVector<MTPUpdate> & other)572 void Updates::feedDifference(
573 		const MTPVector<MTPUser> &users,
574 		const MTPVector<MTPChat> &chats,
575 		const MTPVector<MTPMessage> &msgs,
576 		const MTPVector<MTPUpdate> &other) {
577 	Core::App().checkAutoLock();
578 	session().data().processUsers(users);
579 	session().data().processChats(chats);
580 	feedMessageIds(other);
581 	session().data().processMessages(msgs, NewMessageType::Unread);
582 	feedUpdateVector(other, SkipUpdatePolicy::SkipMessageIds);
583 }
584 
differenceFail(const MTP::Error & error)585 void Updates::differenceFail(const MTP::Error &error) {
586 	LOG(("RPC Error in getDifference: %1 %2: %3").arg(
587 		QString::number(error.code()),
588 		error.type(),
589 		error.description()));
590 	failDifferenceStartTimerFor(nullptr);
591 }
592 
getDifferenceByPts()593 void Updates::getDifferenceByPts() {
594 	auto now = crl::now(), wait = crl::time(0);
595 	if (_getDifferenceTimeByPts) {
596 		if (_getDifferenceTimeByPts > now) {
597 			wait = _getDifferenceTimeByPts - now;
598 		} else {
599 			getDifference();
600 		}
601 	}
602 	for (auto i = _whenGetDiffByPts.begin(); i != _whenGetDiffByPts.cend();) {
603 		if (i->second > now) {
604 			wait = wait ? std::min(wait, i->second - now) : (i->second - now);
605 			++i;
606 		} else {
607 			getChannelDifference(
608 				i->first,
609 				ChannelDifferenceRequest::PtsGapOrShortPoll);
610 			i = _whenGetDiffByPts.erase(i);
611 		}
612 	}
613 	if (wait) {
614 		_byPtsTimer.callOnce(wait);
615 	} else {
616 		_byPtsTimer.cancel();
617 	}
618 }
619 
getDifferenceAfterFail()620 void Updates::getDifferenceAfterFail() {
621 	auto now = crl::now(), wait = crl::time(0);
622 	if (_getDifferenceTimeAfterFail) {
623 		if (_getDifferenceTimeAfterFail > now) {
624 			wait = _getDifferenceTimeAfterFail - now;
625 		} else {
626 			_ptsWaiter.setRequesting(false);
627 			MTP_LOG(0, ("getDifference "
628 				"{ force - after get difference failed }%1"
629 				).arg(_session->mtp().isTestMode() ? " TESTMODE" : ""));
630 			getDifference();
631 		}
632 	}
633 	for (auto i = _whenGetDiffAfterFail.begin(); i != _whenGetDiffAfterFail.cend();) {
634 		if (i->second > now) {
635 			wait = wait ? std::min(wait, i->second - now) : (i->second - now);
636 			++i;
637 		} else {
638 			getChannelDifference(i->first, ChannelDifferenceRequest::AfterFail);
639 			i = _whenGetDiffAfterFail.erase(i);
640 		}
641 	}
642 	if (wait) {
643 		_failDifferenceTimer.callOnce(wait);
644 	} else {
645 		_failDifferenceTimer.cancel();
646 	}
647 }
648 
getDifference()649 void Updates::getDifference() {
650 	_getDifferenceTimeByPts = 0;
651 
652 	if (requestingDifference()) {
653 		return;
654 	}
655 
656 	_bySeqUpdates.clear();
657 	_bySeqTimer.cancel();
658 
659 	_noUpdatesTimer.cancel();
660 	_getDifferenceTimeAfterFail = 0;
661 
662 	_ptsWaiter.setRequesting(true);
663 
664 	api().request(MTPupdates_GetDifference(
665 		MTP_flags(0),
666 		MTP_int(_ptsWaiter.current()),
667 		MTPint(),
668 		MTP_int(_updatesDate),
669 		MTP_int(_updatesQts)
670 	)).done([=](const MTPupdates_Difference &result) {
671 		differenceDone(result);
672 	}).fail([=](const MTP::Error &error) {
673 		differenceFail(error);
674 	}).send();
675 }
676 
getChannelDifference(not_null<ChannelData * > channel,ChannelDifferenceRequest from)677 void Updates::getChannelDifference(
678 		not_null<ChannelData*> channel,
679 		ChannelDifferenceRequest from) {
680 	if (from != ChannelDifferenceRequest::PtsGapOrShortPoll) {
681 		_whenGetDiffByPts.remove(channel);
682 	}
683 
684 	if (!channel->ptsInited() || channel->ptsRequesting()) return;
685 
686 	if (from != ChannelDifferenceRequest::AfterFail) {
687 		_whenGetDiffAfterFail.remove(channel);
688 	}
689 
690 	channel->ptsSetRequesting(true);
691 
692 	auto filter = MTP_channelMessagesFilterEmpty();
693 	auto flags = MTPupdates_GetChannelDifference::Flag::f_force | 0;
694 	if (from != ChannelDifferenceRequest::PtsGapOrShortPoll) {
695 		if (!channel->ptsWaitingForSkipped()) {
696 			flags = 0; // No force flag when requesting for short poll.
697 		}
698 	}
699 	api().request(MTPupdates_GetChannelDifference(
700 		MTP_flags(flags),
701 		channel->inputChannel,
702 		filter,
703 		MTP_int(channel->pts()),
704 		MTP_int(kChannelGetDifferenceLimit)
705 	)).done([=](const MTPupdates_ChannelDifference &result) {
706 		channelDifferenceDone(channel, result);
707 	}).fail([=](const MTP::Error &error) {
708 		channelDifferenceFail(channel, error);
709 	}).send();
710 }
711 
sendPing()712 void Updates::sendPing() {
713 	_session->mtp().ping();
714 }
715 
addActiveChat(rpl::producer<PeerData * > chat)716 void Updates::addActiveChat(rpl::producer<PeerData*> chat) {
717 	const auto key = _activeChats.empty() ? 0 : _activeChats.back().first + 1;
718 	std::move(
719 		chat
720 	) | rpl::start_with_next_done([=](PeerData *peer) {
721 		_activeChats[key].peer = peer;
722 		if (const auto channel = peer ? peer->asChannel() : nullptr) {
723 			channel->ptsWaitingForShortPoll(
724 				kWaitForChannelGetDifference);
725 		}
726 	}, [=] {
727 		_activeChats.erase(key);
728 	}, _activeChats[key].lifetime);
729 }
730 
requestChannelRangeDifference(not_null<History * > history)731 void Updates::requestChannelRangeDifference(not_null<History*> history) {
732 	Expects(history->isChannel());
733 
734 	const auto channel = history->peer->asChannel();
735 	if (const auto requestId = _rangeDifferenceRequests.take(channel)) {
736 		api().request(*requestId).cancel();
737 	}
738 	const auto range = history->rangeForDifferenceRequest();
739 	if (!(range.from < range.till) || !channel->pts()) {
740 		return;
741 	}
742 
743 	MTP_LOG(0, ("getChannelDifference "
744 		"{ good - after channelDifferenceTooLong was received, "
745 		"validating history part }%1"
746 		).arg(_session->mtp().isTestMode() ? " TESTMODE" : ""));
747 	channelRangeDifferenceSend(channel, range, channel->pts());
748 }
749 
channelRangeDifferenceSend(not_null<ChannelData * > channel,MsgRange range,int32 pts)750 void Updates::channelRangeDifferenceSend(
751 		not_null<ChannelData*> channel,
752 		MsgRange range,
753 		int32 pts) {
754 	Expects(range.from < range.till);
755 
756 	const auto limit = range.till - range.from;
757 	const auto filter = MTP_channelMessagesFilter(
758 		MTP_flags(0),
759 		MTP_vector<MTPMessageRange>(1, MTP_messageRange(
760 			MTP_int(range.from),
761 			MTP_int(range.till - 1))));
762 	const auto requestId = api().request(MTPupdates_GetChannelDifference(
763 		MTP_flags(MTPupdates_GetChannelDifference::Flag::f_force),
764 		channel->inputChannel,
765 		filter,
766 		MTP_int(pts),
767 		MTP_int(limit)
768 	)).done([=](const MTPupdates_ChannelDifference &result) {
769 		_rangeDifferenceRequests.remove(channel);
770 		channelRangeDifferenceDone(channel, range, result);
771 	}).fail([=](const MTP::Error &error) {
772 		_rangeDifferenceRequests.remove(channel);
773 	}).send();
774 	_rangeDifferenceRequests.emplace(channel, requestId);
775 }
776 
channelRangeDifferenceDone(not_null<ChannelData * > channel,MsgRange range,const MTPupdates_ChannelDifference & result)777 void Updates::channelRangeDifferenceDone(
778 		not_null<ChannelData*> channel,
779 		MsgRange range,
780 		const MTPupdates_ChannelDifference &result) {
781 	auto nextRequestPts = int32(0);
782 	auto isFinal = true;
783 
784 	switch (result.type()) {
785 	case mtpc_updates_channelDifferenceEmpty: {
786 		const auto &d = result.c_updates_channelDifferenceEmpty();
787 		nextRequestPts = d.vpts().v;
788 		isFinal = d.is_final();
789 	} break;
790 
791 	case mtpc_updates_channelDifferenceTooLong: {
792 		const auto &d = result.c_updates_channelDifferenceTooLong();
793 
794 		_session->data().processUsers(d.vusers());
795 		_session->data().processChats(d.vchats());
796 
797 		nextRequestPts = d.vdialog().match([&](const MTPDdialog &data) {
798 			return data.vpts().value_or_empty();
799 		}, [&](const MTPDdialogFolder &data) {
800 			return 0;
801 		});
802 		isFinal = d.is_final();
803 	} break;
804 
805 	case mtpc_updates_channelDifference: {
806 		const auto &d = result.c_updates_channelDifference();
807 
808 		feedChannelDifference(d);
809 
810 		nextRequestPts = d.vpts().v;
811 		isFinal = d.is_final();
812 	} break;
813 	}
814 
815 	if (!isFinal && nextRequestPts) {
816 		MTP_LOG(0, ("getChannelDifference "
817 			"{ good - after not final channelDifference was received, "
818 			"validating history part }%1"
819 			).arg(_session->mtp().isTestMode() ? " TESTMODE" : ""));
820 		channelRangeDifferenceSend(channel, range, nextRequestPts);
821 	}
822 }
823 
mtpNewSessionCreated()824 void Updates::mtpNewSessionCreated() {
825 	Core::App().checkAutoLock();
826 	_updatesSeq = 0;
827 	MTP_LOG(0, ("getDifference { after new_session_created }%1"
828 		).arg(_session->mtp().isTestMode() ? " TESTMODE" : ""));
829 	getDifference();
830 }
831 
mtpUpdateReceived(const MTPUpdates & updates)832 void Updates::mtpUpdateReceived(const MTPUpdates &updates) {
833 	Core::App().checkAutoLock();
834 	_lastUpdateTime = crl::now();
835 	_noUpdatesTimer.callOnce(kNoUpdatesTimeout);
836 	if (!requestingDifference()
837 		|| HasForceLogoutNotification(updates)) {
838 		applyUpdates(updates);
839 	} else {
840 		applyGroupCallParticipantUpdates(updates);
841 	}
842 }
843 
applyGroupCallParticipantUpdates(const MTPUpdates & updates)844 void Updates::applyGroupCallParticipantUpdates(const MTPUpdates &updates) {
845 	updates.match([&](const MTPDupdates &data) {
846 		session().data().processUsers(data.vusers());
847 		session().data().processChats(data.vchats());
848 		feedUpdateVector(
849 			data.vupdates(),
850 			SkipUpdatePolicy::SkipExceptGroupCallParticipants);
851 	}, [&](const MTPDupdatesCombined &data) {
852 		session().data().processUsers(data.vusers());
853 		session().data().processChats(data.vchats());
854 		feedUpdateVector(
855 			data.vupdates(),
856 			SkipUpdatePolicy::SkipExceptGroupCallParticipants);
857 	}, [&](const MTPDupdateShort &data) {
858 		if (data.vupdate().type() == mtpc_updateGroupCallParticipants) {
859 			feedUpdate(data.vupdate());
860 		}
861 	}, [](const auto &) {
862 	});
863 }
864 
pts() const865 int32 Updates::pts() const {
866 	return _ptsWaiter.current();
867 }
868 
updateOnline(crl::time lastNonIdleTime)869 void Updates::updateOnline(crl::time lastNonIdleTime) {
870 	updateOnline(lastNonIdleTime, false);
871 }
872 
isIdle() const873 bool Updates::isIdle() const {
874 	return _isIdle.current();
875 }
876 
isIdleValue() const877 rpl::producer<bool> Updates::isIdleValue() const {
878 	return _isIdle.value();
879 }
880 
updateOnline(crl::time lastNonIdleTime,bool gotOtherOffline)881 void Updates::updateOnline(crl::time lastNonIdleTime, bool gotOtherOffline) {
882 	if (!lastNonIdleTime) {
883 		lastNonIdleTime = Core::App().lastNonIdleTime();
884 	}
885 	crl::on_main(&session(), [=] {
886 		Core::App().checkAutoLock(lastNonIdleTime);
887 	});
888 
889 	const auto &config = _session->serverConfig();
890 	bool isOnline = Core::App().hasActiveWindow(&session());
891 	int updateIn = config.onlineUpdatePeriod;
892 	Assert(updateIn >= 0);
893 	if (isOnline) {
894 		const auto idle = crl::now() - lastNonIdleTime;
895 		if (idle >= config.offlineIdleTimeout) {
896 			isOnline = false;
897 			if (!isIdle()) {
898 				_isIdle = true;
899 				_idleFinishTimer.callOnce(900);
900 			}
901 		} else {
902 			updateIn = qMin(updateIn, int(config.offlineIdleTimeout - idle));
903 			Assert(updateIn >= 0);
904 		}
905 	}
906 	auto ms = crl::now();
907 	if (isOnline != _lastWasOnline
908 		|| (isOnline && _lastSetOnline + config.onlineUpdatePeriod <= ms)
909 		|| (isOnline && gotOtherOffline)) {
910 		api().request(base::take(_onlineRequest)).cancel();
911 
912 		_lastWasOnline = isOnline;
913 		_lastSetOnline = ms;
914 		if (!App::quitting()) {
915 			_onlineRequest = api().request(MTPaccount_UpdateStatus(
916 				MTP_bool(!isOnline)
917 			)).send();
918 		} else {
919 			_onlineRequest = api().request(MTPaccount_UpdateStatus(
920 				MTP_bool(!isOnline)
921 			)).done([=](const MTPBool &result) {
922 				Core::App().quitPreventFinished();
923 			}).fail([=](const MTP::Error &error) {
924 				Core::App().quitPreventFinished();
925 			}).send();
926 		}
927 
928 		const auto self = session().user();
929 		self->onlineTill = base::unixtime::now() + (isOnline ? (config.onlineUpdatePeriod / 1000) : -1);
930 		session().changes().peerUpdated(
931 			self,
932 			Data::PeerUpdate::Flag::OnlineStatus);
933 		if (!isOnline) { // Went offline, so we need to save message draft to the cloud.
934 			api().saveCurrentDraftToCloud();
935 		}
936 
937 		_lastSetOnline = ms;
938 	} else if (isOnline) {
939 		updateIn = qMin(updateIn, int(_lastSetOnline + config.onlineUpdatePeriod - ms));
940 		Assert(updateIn >= 0);
941 	}
942 	_onlineTimer.callOnce(updateIn);
943 }
944 
checkIdleFinish(crl::time lastNonIdleTime)945 void Updates::checkIdleFinish(crl::time lastNonIdleTime) {
946 	if (!lastNonIdleTime) {
947 		lastNonIdleTime = Core::App().lastNonIdleTime();
948 	}
949 	if (crl::now() - lastNonIdleTime
950 		< _session->serverConfig().offlineIdleTimeout) {
951 		updateOnline(lastNonIdleTime);
952 		_idleFinishTimer.cancel();
953 		_isIdle = false;
954 	} else {
955 		_idleFinishTimer.callOnce(900);
956 	}
957 }
958 
lastWasOnline() const959 bool Updates::lastWasOnline() const {
960 	return _lastWasOnline;
961 }
962 
lastSetOnline() const963 crl::time Updates::lastSetOnline() const {
964 	return _lastSetOnline;
965 }
966 
isQuitPrevent()967 bool Updates::isQuitPrevent() {
968 	if (!_lastWasOnline) {
969 		return false;
970 	}
971 	LOG(("Api::Updates prevents quit, sending offline status..."));
972 	updateOnline(crl::now());
973 	return true;
974 }
975 
handleSendActionUpdate(PeerId peerId,MsgId rootId,PeerId fromId,const MTPSendMessageAction & action)976 void Updates::handleSendActionUpdate(
977 		PeerId peerId,
978 		MsgId rootId,
979 		PeerId fromId,
980 		const MTPSendMessageAction &action) {
981 	const auto history = session().data().historyLoaded(peerId);
982 	if (!history) {
983 		return;
984 	}
985 	const auto peer = history->peer;
986 	const auto from = (fromId == session().userPeerId())
987 		? session().user().get()
988 		: session().data().peerLoaded(fromId);
989 	if (action.type() == mtpc_speakingInGroupCallAction) {
990 		handleSpeakingInCall(peer, fromId, from);
991 	}
992 	if (!from || !from->isUser() || from->isSelf()) {
993 		return;
994 	} else if (action.type() == mtpc_sendMessageEmojiInteraction) {
995 		handleEmojiInteraction(peer, action.c_sendMessageEmojiInteraction());
996 		return;
997 	} else if (action.type() == mtpc_sendMessageEmojiInteractionSeen) {
998 		const auto &data = action.c_sendMessageEmojiInteractionSeen();
999 		handleEmojiInteraction(peer, qs(data.vemoticon()));
1000 		return;
1001 	}
1002 	const auto when = requestingDifference()
1003 		? 0
1004 		: base::unixtime::now();
1005 	session().data().sendActionManager().registerFor(
1006 		history,
1007 		rootId,
1008 		from->asUser(),
1009 		action,
1010 		when);
1011 }
1012 
handleEmojiInteraction(not_null<PeerData * > peer,const MTPDsendMessageEmojiInteraction & data)1013 void Updates::handleEmojiInteraction(
1014 		not_null<PeerData*> peer,
1015 		const MTPDsendMessageEmojiInteraction &data) {
1016 	const auto json = data.vinteraction().match([&](
1017 			const MTPDdataJSON &data) {
1018 		return data.vdata().v;
1019 	});
1020 	handleEmojiInteraction(
1021 		peer,
1022 		data.vmsg_id().v,
1023 		qs(data.vemoticon()),
1024 		ChatHelpers::EmojiInteractions::Parse(json));
1025 }
1026 
handleSpeakingInCall(not_null<PeerData * > peer,PeerId participantPeerId,PeerData * participantPeerLoaded)1027 void Updates::handleSpeakingInCall(
1028 		not_null<PeerData*> peer,
1029 		PeerId participantPeerId,
1030 		PeerData *participantPeerLoaded) {
1031 	if (!peer->isChat() && !peer->isChannel()) {
1032 		return;
1033 	}
1034 	const auto call = peer->groupCall();
1035 	const auto now = crl::now();
1036 	if (call) {
1037 		call->applyActiveUpdate(
1038 			participantPeerId,
1039 			Data::LastSpokeTimes{ .anything = now, .voice = now },
1040 			participantPeerLoaded);
1041 	} else {
1042 		const auto chat = peer->asChat();
1043 		const auto channel = peer->asChannel();
1044 		const auto active = chat
1045 			? (chat->flags() & ChatDataFlag::CallActive)
1046 			: (channel->flags() & ChannelDataFlag::CallActive);
1047 		if (active) {
1048 			_pendingSpeakingCallParticipants.emplace(
1049 				peer).first->second[participantPeerId] = now;
1050 			if (peerIsUser(participantPeerId)) {
1051 				session().api().requestFullPeer(peer);
1052 			}
1053 		}
1054 	}
1055 }
1056 
handleEmojiInteraction(not_null<PeerData * > peer,MsgId messageId,const QString & emoticon,ChatHelpers::EmojiInteractionsBunch bunch)1057 void Updates::handleEmojiInteraction(
1058 		not_null<PeerData*> peer,
1059 		MsgId messageId,
1060 		const QString &emoticon,
1061 		ChatHelpers::EmojiInteractionsBunch bunch) {
1062 	if (session().windows().empty()) {
1063 		return;
1064 	}
1065 	const auto window = session().windows().front();
1066 	window->emojiInteractions().startIncoming(
1067 		peer,
1068 		messageId,
1069 		emoticon,
1070 		std::move(bunch));
1071 }
1072 
handleEmojiInteraction(not_null<PeerData * > peer,const QString & emoticon)1073 void Updates::handleEmojiInteraction(
1074 		not_null<PeerData*> peer,
1075 		const QString &emoticon) {
1076 	if (session().windows().empty()) {
1077 		return;
1078 	}
1079 	const auto window = session().windows().front();
1080 	window->emojiInteractions().seenOutgoing(peer, emoticon);
1081 }
1082 
applyUpdatesNoPtsCheck(const MTPUpdates & updates)1083 void Updates::applyUpdatesNoPtsCheck(const MTPUpdates &updates) {
1084 	switch (updates.type()) {
1085 	case mtpc_updateShortMessage: {
1086 		const auto &d = updates.c_updateShortMessage();
1087 		const auto flags = mtpCastFlags(d.vflags().v)
1088 			| MTPDmessage::Flag::f_from_id;
1089 		_session->data().addNewMessage(
1090 			MTP_message(
1091 				MTP_flags(flags),
1092 				d.vid(),
1093 				(d.is_out()
1094 					? peerToMTP(_session->userPeerId())
1095 					: MTP_peerUser(d.vuser_id())),
1096 				MTP_peerUser(d.vuser_id()),
1097 				d.vfwd_from() ? *d.vfwd_from() : MTPMessageFwdHeader(),
1098 				MTP_long(d.vvia_bot_id().value_or_empty()),
1099 				d.vreply_to() ? *d.vreply_to() : MTPMessageReplyHeader(),
1100 				d.vdate(),
1101 				d.vmessage(),
1102 				MTP_messageMediaEmpty(),
1103 				MTPReplyMarkup(),
1104 				MTP_vector<MTPMessageEntity>(d.ventities().value_or_empty()),
1105 				MTPint(), // views
1106 				MTPint(), // forwards
1107 				MTPMessageReplies(),
1108 				MTPint(), // edit_date
1109 				MTPstring(),
1110 				MTPlong(),
1111 				//MTPMessageReactions(),
1112 				MTPVector<MTPRestrictionReason>(),
1113 				MTP_int(d.vttl_period().value_or_empty())),
1114 			MessageFlags(),
1115 			NewMessageType::Unread);
1116 	} break;
1117 
1118 	case mtpc_updateShortChatMessage: {
1119 		const auto &d = updates.c_updateShortChatMessage();
1120 		const auto flags = mtpCastFlags(d.vflags().v)
1121 			| MTPDmessage::Flag::f_from_id;
1122 		_session->data().addNewMessage(
1123 			MTP_message(
1124 				MTP_flags(flags),
1125 				d.vid(),
1126 				MTP_peerUser(d.vfrom_id()),
1127 				MTP_peerChat(d.vchat_id()),
1128 				d.vfwd_from() ? *d.vfwd_from() : MTPMessageFwdHeader(),
1129 				MTP_long(d.vvia_bot_id().value_or_empty()),
1130 				d.vreply_to() ? *d.vreply_to() : MTPMessageReplyHeader(),
1131 				d.vdate(),
1132 				d.vmessage(),
1133 				MTP_messageMediaEmpty(),
1134 				MTPReplyMarkup(),
1135 				MTP_vector<MTPMessageEntity>(d.ventities().value_or_empty()),
1136 				MTPint(), // views
1137 				MTPint(), // forwards
1138 				MTPMessageReplies(),
1139 				MTPint(), // edit_date
1140 				MTPstring(),
1141 				MTPlong(),
1142 				//MTPMessageReactions(),
1143 				MTPVector<MTPRestrictionReason>(),
1144 				MTP_int(d.vttl_period().value_or_empty())),
1145 			MessageFlags(),
1146 			NewMessageType::Unread);
1147 	} break;
1148 
1149 	case mtpc_updateShortSentMessage: {
1150 		auto &d = updates.c_updateShortSentMessage();
1151 		Q_UNUSED(d); // Sent message data was applied anyway.
1152 	} break;
1153 
1154 	default: Unexpected("Type in applyUpdatesNoPtsCheck()");
1155 	}
1156 }
1157 
applyUpdateNoPtsCheck(const MTPUpdate & update)1158 void Updates::applyUpdateNoPtsCheck(const MTPUpdate &update) {
1159 	switch (update.type()) {
1160 	case mtpc_updateNewMessage: {
1161 		auto &d = update.c_updateNewMessage();
1162 		auto needToAdd = true;
1163 		if (d.vmessage().type() == mtpc_message) { // index forwarded messages to links _overview
1164 			const auto &data = d.vmessage().c_message();
1165 			if (_session->data().checkEntitiesAndViewsUpdate(data)) { // already in blocks
1166 				LOG(("Skipping message, because it is already in blocks!"));
1167 				needToAdd = false;
1168 			}
1169 			ProcessScheduledMessageWithElapsedTime(_session, needToAdd, data);
1170 		}
1171 		if (needToAdd) {
1172 			_session->data().addNewMessage(
1173 				d.vmessage(),
1174 				MessageFlags(),
1175 				NewMessageType::Unread);
1176 		}
1177 	} break;
1178 
1179 	case mtpc_updateReadMessagesContents: {
1180 		const auto &d = update.c_updateReadMessagesContents();
1181 		auto possiblyReadMentions = base::flat_set<MsgId>();
1182 		for (const auto &msgId : d.vmessages().v) {
1183 			if (const auto item = _session->data().message(NoChannel, msgId.v)) {
1184 				if (item->isUnreadMedia() || item->isUnreadMention()) {
1185 					item->markMediaRead();
1186 					_session->data().requestItemRepaint(item);
1187 
1188 					if (item->out()
1189 						&& item->history()->peer->isUser()
1190 						&& !requestingDifference()) {
1191 						item->history()->peer->asUser()->madeAction(base::unixtime::now());
1192 					}
1193 				}
1194 			} else {
1195 				// Perhaps it was an unread mention!
1196 				possiblyReadMentions.insert(msgId.v);
1197 			}
1198 		}
1199 		session().api().checkForUnreadMentions(possiblyReadMentions);
1200 	} break;
1201 
1202 	case mtpc_updateReadHistoryInbox: {
1203 		const auto &d = update.c_updateReadHistoryInbox();
1204 		const auto peer = peerFromMTP(d.vpeer());
1205 		if (const auto history = _session->data().historyLoaded(peer)) {
1206 			const auto folderId = d.vfolder_id().value_or_empty();
1207 			history->applyInboxReadUpdate(
1208 				folderId,
1209 				d.vmax_id().v,
1210 				d.vstill_unread_count().v);
1211 		}
1212 	} break;
1213 
1214 	case mtpc_updateReadHistoryOutbox: {
1215 		const auto &d = update.c_updateReadHistoryOutbox();
1216 		const auto peer = peerFromMTP(d.vpeer());
1217 		if (const auto history = _session->data().historyLoaded(peer)) {
1218 			history->outboxRead(d.vmax_id().v);
1219 			if (!requestingDifference()) {
1220 				if (const auto user = history->peer->asUser()) {
1221 					user->madeAction(base::unixtime::now());
1222 				}
1223 			}
1224 		}
1225 	} break;
1226 
1227 	case mtpc_updateWebPage: {
1228 		auto &d = update.c_updateWebPage();
1229 		Q_UNUSED(d); // Web page was updated anyway.
1230 	} break;
1231 
1232 	case mtpc_updateFolderPeers: {
1233 		const auto &data = update.c_updateFolderPeers();
1234 		auto &owner = _session->data();
1235 		for (const auto &peer : data.vfolder_peers().v) {
1236 			peer.match([&](const MTPDfolderPeer &data) {
1237 				const auto peerId = peerFromMTP(data.vpeer());
1238 				if (const auto history = owner.historyLoaded(peerId)) {
1239 					if (const auto folderId = data.vfolder_id().v) {
1240 						history->setFolder(owner.folder(folderId));
1241 					} else {
1242 						history->clearFolder();
1243 					}
1244 				}
1245 			});
1246 		}
1247 	} break;
1248 
1249 	case mtpc_updateDeleteMessages: {
1250 		auto &d = update.c_updateDeleteMessages();
1251 		_session->data().processMessagesDeleted(NoChannel, d.vmessages().v);
1252 	} break;
1253 
1254 	case mtpc_updateNewChannelMessage: {
1255 		auto &d = update.c_updateNewChannelMessage();
1256 		auto needToAdd = true;
1257 		if (d.vmessage().type() == mtpc_message) { // index forwarded messages to links _overview
1258 			const auto &data = d.vmessage().c_message();
1259 			if (_session->data().checkEntitiesAndViewsUpdate(data)) { // already in blocks
1260 				LOG(("Skipping message, because it is already in blocks!"));
1261 				needToAdd = false;
1262 			}
1263 			ProcessScheduledMessageWithElapsedTime(_session, needToAdd, data);
1264 		}
1265 		if (needToAdd) {
1266 			_session->data().addNewMessage(
1267 				d.vmessage(),
1268 				MessageFlags(),
1269 				NewMessageType::Unread);
1270 		}
1271 	} break;
1272 
1273 	case mtpc_updateEditChannelMessage: {
1274 		auto &d = update.c_updateEditChannelMessage();
1275 		_session->data().updateEditedMessage(d.vmessage());
1276 	} break;
1277 
1278 	case mtpc_updatePinnedChannelMessages: {
1279 		const auto &d = update.c_updatePinnedChannelMessages();
1280 		const auto channelId = d.vchannel_id().v;
1281 		for (const auto &msgId : d.vmessages().v) {
1282 			const auto item = session().data().message(channelId, msgId.v);
1283 			if (item) {
1284 				item->setIsPinned(d.is_pinned());
1285 			}
1286 		}
1287 	} break;
1288 
1289 	case mtpc_updateEditMessage: {
1290 		auto &d = update.c_updateEditMessage();
1291 		_session->data().updateEditedMessage(d.vmessage());
1292 	} break;
1293 
1294 	case mtpc_updateChannelWebPage: {
1295 		auto &d = update.c_updateChannelWebPage();
1296 		Q_UNUSED(d); // Web page was updated anyway.
1297 	} break;
1298 
1299 	case mtpc_updateDeleteChannelMessages: {
1300 		auto &d = update.c_updateDeleteChannelMessages();
1301 		_session->data().processMessagesDeleted(d.vchannel_id().v, d.vmessages().v);
1302 	} break;
1303 
1304 	case mtpc_updatePinnedMessages: {
1305 		const auto &d = update.c_updatePinnedMessages();
1306 		for (const auto &msgId : d.vmessages().v) {
1307 			const auto item = session().data().message(0, msgId.v);
1308 			if (item) {
1309 				item->setIsPinned(d.is_pinned());
1310 			}
1311 		}
1312 	} break;
1313 
1314 	default: Unexpected("Type in applyUpdateNoPtsCheck()");
1315 	}
1316 }
1317 
applyUpdates(const MTPUpdates & updates,uint64 sentMessageRandomId)1318 void Updates::applyUpdates(
1319 		const MTPUpdates &updates,
1320 		uint64 sentMessageRandomId) {
1321 	const auto randomId = sentMessageRandomId;
1322 
1323 	switch (updates.type()) {
1324 	case mtpc_updates: {
1325 		auto &d = updates.c_updates();
1326 		if (d.vseq().v) {
1327 			if (d.vseq().v <= _updatesSeq) {
1328 				return;
1329 			}
1330 			if (d.vseq().v > _updatesSeq + 1) {
1331 				_bySeqUpdates.emplace(d.vseq().v, updates);
1332 				_bySeqTimer.callOnce(PtsWaiter::kWaitForSkippedTimeout);
1333 				return;
1334 			}
1335 		}
1336 
1337 		session().data().processUsers(d.vusers());
1338 		session().data().processChats(d.vchats());
1339 		feedUpdateVector(d.vupdates());
1340 
1341 		setState(0, d.vdate().v, _updatesQts, d.vseq().v);
1342 	} break;
1343 
1344 	case mtpc_updatesCombined: {
1345 		auto &d = updates.c_updatesCombined();
1346 		if (d.vseq_start().v) {
1347 			if (d.vseq_start().v <= _updatesSeq) {
1348 				return;
1349 			}
1350 			if (d.vseq_start().v > _updatesSeq + 1) {
1351 				_bySeqUpdates.emplace(d.vseq_start().v, updates);
1352 				_bySeqTimer.callOnce(PtsWaiter::kWaitForSkippedTimeout);
1353 				return;
1354 			}
1355 		}
1356 
1357 		session().data().processUsers(d.vusers());
1358 		session().data().processChats(d.vchats());
1359 		feedUpdateVector(d.vupdates());
1360 
1361 		setState(0, d.vdate().v, _updatesQts, d.vseq().v);
1362 	} break;
1363 
1364 	case mtpc_updateShort: {
1365 		auto &d = updates.c_updateShort();
1366 		feedUpdate(d.vupdate());
1367 
1368 		setState(0, d.vdate().v, _updatesQts, _updatesSeq);
1369 	} break;
1370 
1371 	case mtpc_updateShortMessage: {
1372 		auto &d = updates.c_updateShortMessage();
1373 		const auto viaBotId = d.vvia_bot_id();
1374 		const auto entities = d.ventities();
1375 		const auto fwd = d.vfwd_from();
1376 		if (!session().data().userLoaded(d.vuser_id())
1377 			|| (viaBotId && !session().data().userLoaded(*viaBotId))
1378 			|| (entities && !MentionUsersLoaded(&session(), *entities))
1379 			|| (fwd && !ForwardedInfoDataLoaded(&session(), *fwd))) {
1380 			MTP_LOG(0, ("getDifference "
1381 				"{ good - getting user for updateShortMessage }%1"
1382 				).arg(_session->mtp().isTestMode() ? " TESTMODE" : ""));
1383 			return getDifference();
1384 		}
1385 		if (updateAndApply(d.vpts().v, d.vpts_count().v, updates)) {
1386 			// Update date as well.
1387 			setState(0, d.vdate().v, _updatesQts, _updatesSeq);
1388 		}
1389 	} break;
1390 
1391 	case mtpc_updateShortChatMessage: {
1392 		auto &d = updates.c_updateShortChatMessage();
1393 		const auto noFrom = !session().data().userLoaded(d.vfrom_id());
1394 		const auto chat = session().data().chatLoaded(d.vchat_id());
1395 		const auto viaBotId = d.vvia_bot_id();
1396 		const auto entities = d.ventities();
1397 		const auto fwd = d.vfwd_from();
1398 		if (!chat
1399 			|| noFrom
1400 			|| (viaBotId && !session().data().userLoaded(*viaBotId))
1401 			|| (entities && !MentionUsersLoaded(&session(), *entities))
1402 			|| (fwd && !ForwardedInfoDataLoaded(&session(), *fwd))) {
1403 			MTP_LOG(0, ("getDifference "
1404 				"{ good - getting user for updateShortChatMessage }%1"
1405 				).arg(_session->mtp().isTestMode() ? " TESTMODE" : ""));
1406 			if (chat && noFrom) {
1407 				session().api().requestFullPeer(chat);
1408 			}
1409 			return getDifference();
1410 		}
1411 		if (updateAndApply(d.vpts().v, d.vpts_count().v, updates)) {
1412 			// Update date as well.
1413 			setState(0, d.vdate().v, _updatesQts, _updatesSeq);
1414 		}
1415 	} break;
1416 
1417 	case mtpc_updateShortSentMessage: {
1418 		auto &d = updates.c_updateShortSentMessage();
1419 		if (!IsServerMsgId(d.vid().v)) {
1420 			LOG(("API Error: Bad msgId got from server: %1").arg(d.vid().v));
1421 		} else if (randomId) {
1422 			auto &owner = session().data();
1423 			const auto sent = owner.messageSentData(randomId);
1424 			const auto lookupMessage = [&] {
1425 				return sent.peerId
1426 					? owner.message(peerToChannel(sent.peerId), d.vid().v)
1427 					: nullptr;
1428 			};
1429 			if (const auto id = owner.messageIdByRandomId(randomId)) {
1430 				const auto local = owner.message(id);
1431 				if (local && local->isScheduled()) {
1432 					owner.scheduledMessages().sendNowSimpleMessage(d, local);
1433 				}
1434 			}
1435 			const auto wasAlready = (lookupMessage() != nullptr);
1436 			feedUpdate(MTP_updateMessageID(d.vid(), MTP_long(randomId))); // ignore real date
1437 			if (const auto item = lookupMessage()) {
1438 				const auto list = d.ventities();
1439 				if (list && !MentionUsersLoaded(&session(), *list)) {
1440 					session().api().requestMessageData(
1441 						item->history()->peer->asChannel(),
1442 						item->id,
1443 						ApiWrap::RequestMessageDataCallback());
1444 				}
1445 				item->applySentMessage(sent.text, d, wasAlready);
1446 			}
1447 		}
1448 
1449 		if (updateAndApply(d.vpts().v, d.vpts_count().v, updates)) {
1450 			// Update date as well.
1451 			setState(0, d.vdate().v, _updatesQts, _updatesSeq);
1452 		}
1453 	} break;
1454 
1455 	case mtpc_updatesTooLong: {
1456 		MTP_LOG(0, ("getDifference "
1457 			"{ good - updatesTooLong received }%1"
1458 			).arg(_session->mtp().isTestMode() ? " TESTMODE" : ""));
1459 		return getDifference();
1460 	} break;
1461 	}
1462 	session().data().sendHistoryChangeNotifications();
1463 }
1464 
feedUpdate(const MTPUpdate & update)1465 void Updates::feedUpdate(const MTPUpdate &update) {
1466 	switch (update.type()) {
1467 
1468 	// New messages.
1469 	case mtpc_updateNewMessage: {
1470 		auto &d = update.c_updateNewMessage();
1471 
1472 		const auto isDataLoaded = AllDataLoadedForMessage(&session(), d.vmessage());
1473 		if (!requestingDifference() && isDataLoaded != DataIsLoadedResult::Ok) {
1474 			MTP_LOG(0, ("getDifference "
1475 				"{ good - after not all data loaded in updateNewMessage }%1"
1476 				).arg(_session->mtp().isTestMode() ? " TESTMODE" : ""));
1477 
1478 			// This can be if this update was created by grouping
1479 			// some short message update into an updates vector.
1480 			return getDifference();
1481 		}
1482 
1483 		updateAndApply(d.vpts().v, d.vpts_count().v, update);
1484 	} break;
1485 
1486 	case mtpc_updateNewChannelMessage: {
1487 		auto &d = update.c_updateNewChannelMessage();
1488 		auto channel = session().data().channelLoaded(peerToChannel(PeerFromMessage(d.vmessage())));
1489 		const auto isDataLoaded = AllDataLoadedForMessage(&session(), d.vmessage());
1490 		if (!requestingDifference() && (!channel || isDataLoaded != DataIsLoadedResult::Ok)) {
1491 			MTP_LOG(0, ("getDifference "
1492 				"{ good - after not all data loaded in updateNewChannelMessage }%1"
1493 				).arg(_session->mtp().isTestMode() ? " TESTMODE" : ""));
1494 
1495 			// Request last active supergroup participants if the 'from' user was not loaded yet.
1496 			// This will optimize similar getDifference() calls for almost all next messages.
1497 			if (isDataLoaded == DataIsLoadedResult::FromNotLoaded && channel && channel->isMegagroup()) {
1498 				if (channel->mgInfo->lastParticipants.size() < _session->serverConfig().chatSizeMax
1499 					&& (channel->mgInfo->lastParticipants.empty()
1500 						|| channel->mgInfo->lastParticipants.size() < channel->membersCount())) {
1501 					session().api().requestLastParticipants(channel);
1502 				}
1503 			}
1504 
1505 			if (!_byMinChannelTimer.isActive()) { // getDifference after timeout
1506 				_byMinChannelTimer.callOnce(PtsWaiter::kWaitForSkippedTimeout);
1507 			}
1508 			return;
1509 		}
1510 		if (channel && !_handlingChannelDifference) {
1511 			if (channel->ptsRequesting()) { // skip global updates while getting channel difference
1512 				return;
1513 			}
1514 			channel->ptsUpdateAndApply(d.vpts().v, d.vpts_count().v, update);
1515 		} else {
1516 			applyUpdateNoPtsCheck(update);
1517 		}
1518 	} break;
1519 
1520 	case mtpc_updateMessageID: {
1521 		const auto &d = update.c_updateMessageID();
1522 		const auto randomId = d.vrandom_id().v;
1523 		if (const auto id = session().data().messageIdByRandomId(randomId)) {
1524 			const auto newId = d.vid().v;
1525 			if (const auto local = session().data().message(id)) {
1526 				if (local->isScheduled()) {
1527 					session().data().scheduledMessages().apply(d, local);
1528 				} else {
1529 					const auto channel = id.channel;
1530 					const auto existing = session().data().message(
1531 						channel,
1532 						newId);
1533 					if (existing && !local->mainView()) {
1534 						const auto history = local->history();
1535 						local->destroy();
1536 						history->requestChatListMessage();
1537 					} else {
1538 						if (existing) {
1539 							existing->destroy();
1540 						}
1541 						local->setRealId(d.vid().v);
1542 					}
1543 				}
1544 			}
1545 			session().data().unregisterMessageRandomId(randomId);
1546 		}
1547 		session().data().unregisterMessageSentData(randomId);
1548 	} break;
1549 
1550 	// Message contents being read.
1551 	case mtpc_updateReadMessagesContents: {
1552 		auto &d = update.c_updateReadMessagesContents();
1553 		updateAndApply(d.vpts().v, d.vpts_count().v, update);
1554 	} break;
1555 
1556 	case mtpc_updateChannelReadMessagesContents: {
1557 		auto &d = update.c_updateChannelReadMessagesContents();
1558 		auto channel = session().data().channelLoaded(d.vchannel_id());
1559 		if (!channel) {
1560 			if (!_byMinChannelTimer.isActive()) {
1561 				// getDifference after timeout.
1562 				_byMinChannelTimer.callOnce(PtsWaiter::kWaitForSkippedTimeout);
1563 			}
1564 			return;
1565 		}
1566 		auto possiblyReadMentions = base::flat_set<MsgId>();
1567 		for (const auto &msgId : d.vmessages().v) {
1568 			if (auto item = session().data().message(channel, msgId.v)) {
1569 				if (item->isUnreadMedia() || item->isUnreadMention()) {
1570 					item->markMediaRead();
1571 					session().data().requestItemRepaint(item);
1572 				}
1573 			} else {
1574 				// Perhaps it was an unread mention!
1575 				possiblyReadMentions.insert(msgId.v);
1576 			}
1577 		}
1578 		session().api().checkForUnreadMentions(possiblyReadMentions, channel);
1579 	} break;
1580 
1581 	// Edited messages.
1582 	case mtpc_updateEditMessage: {
1583 		auto &d = update.c_updateEditMessage();
1584 		updateAndApply(d.vpts().v, d.vpts_count().v, update);
1585 	} break;
1586 
1587 	case mtpc_updateEditChannelMessage: {
1588 		auto &d = update.c_updateEditChannelMessage();
1589 		auto channel = session().data().channelLoaded(peerToChannel(PeerFromMessage(d.vmessage())));
1590 
1591 		if (channel && !_handlingChannelDifference) {
1592 			if (channel->ptsRequesting()) { // skip global updates while getting channel difference
1593 				return;
1594 			} else {
1595 				channel->ptsUpdateAndApply(d.vpts().v, d.vpts_count().v, update);
1596 			}
1597 		} else {
1598 			applyUpdateNoPtsCheck(update);
1599 		}
1600 	} break;
1601 
1602 	case mtpc_updatePinnedChannelMessages: {
1603 		auto &d = update.c_updatePinnedChannelMessages();
1604 		auto channel = session().data().channelLoaded(d.vchannel_id());
1605 
1606 		if (channel && !_handlingChannelDifference) {
1607 			if (channel->ptsRequesting()) { // skip global updates while getting channel difference
1608 				return;
1609 			} else {
1610 				channel->ptsUpdateAndApply(d.vpts().v, d.vpts_count().v, update);
1611 			}
1612 		} else {
1613 			applyUpdateNoPtsCheck(update);
1614 		}
1615 	} break;
1616 
1617 	// Messages being read.
1618 	case mtpc_updateReadHistoryInbox: {
1619 		auto &d = update.c_updateReadHistoryInbox();
1620 		updateAndApply(d.vpts().v, d.vpts_count().v, update);
1621 	} break;
1622 
1623 	case mtpc_updateReadHistoryOutbox: {
1624 		auto &d = update.c_updateReadHistoryOutbox();
1625 		updateAndApply(d.vpts().v, d.vpts_count().v, update);
1626 	} break;
1627 
1628 	case mtpc_updateReadChannelInbox: {
1629 		const auto &d = update.c_updateReadChannelInbox();
1630 		const auto peer = peerFromChannel(d.vchannel_id().v);
1631 		if (const auto history = session().data().historyLoaded(peer)) {
1632 			history->applyInboxReadUpdate(
1633 				d.vfolder_id().value_or_empty(),
1634 				d.vmax_id().v,
1635 				d.vstill_unread_count().v,
1636 				d.vpts().v);
1637 		}
1638 	} break;
1639 
1640 	case mtpc_updateReadChannelOutbox: {
1641 		const auto &d = update.c_updateReadChannelOutbox();
1642 		const auto peer = peerFromChannel(d.vchannel_id().v);
1643 		if (const auto history = session().data().historyLoaded(peer)) {
1644 			history->outboxRead(d.vmax_id().v);
1645 			if (!requestingDifference()) {
1646 				if (const auto user = history->peer->asUser()) {
1647 					user->madeAction(base::unixtime::now());
1648 				}
1649 			}
1650 		}
1651 	} break;
1652 
1653 	case mtpc_updateDialogUnreadMark: {
1654 		const auto &data = update.c_updateDialogUnreadMark();
1655 		data.vpeer().match(
1656 		[&](const MTPDdialogPeer &dialog) {
1657 			const auto id = peerFromMTP(dialog.vpeer());
1658 			if (const auto history = session().data().historyLoaded(id)) {
1659 				history->setUnreadMark(data.is_unread());
1660 			}
1661 		}, [&](const MTPDdialogPeerFolder &dialog) {
1662 			//const auto id = dialog.vfolder_id().v; // #TODO archive
1663 			//if (const auto folder = session().data().folderLoaded(id)) {
1664 			//	folder->setUnreadMark(data.is_unread());
1665 			//}
1666 		});
1667 	} break;
1668 
1669 	case mtpc_updateFolderPeers: {
1670 		const auto &data = update.c_updateFolderPeers();
1671 
1672 		updateAndApply(data.vpts().v, data.vpts_count().v, update);
1673 	} break;
1674 
1675 	case mtpc_updateDialogFilter:
1676 	case mtpc_updateDialogFilterOrder:
1677 	case mtpc_updateDialogFilters: {
1678 		session().data().chatsFilters().apply(update);
1679 	} break;
1680 
1681 	// Deleted messages.
1682 	case mtpc_updateDeleteMessages: {
1683 		auto &d = update.c_updateDeleteMessages();
1684 
1685 		updateAndApply(d.vpts().v, d.vpts_count().v, update);
1686 	} break;
1687 
1688 	case mtpc_updateDeleteChannelMessages: {
1689 		auto &d = update.c_updateDeleteChannelMessages();
1690 		auto channel = session().data().channelLoaded(d.vchannel_id());
1691 
1692 		if (channel && !_handlingChannelDifference) {
1693 			if (channel->ptsRequesting()) { // skip global updates while getting channel difference
1694 				return;
1695 			}
1696 			channel->ptsUpdateAndApply(d.vpts().v, d.vpts_count().v, update);
1697 		} else {
1698 			applyUpdateNoPtsCheck(update);
1699 		}
1700 	} break;
1701 
1702 	case mtpc_updateNewScheduledMessage: {
1703 		const auto &d = update.c_updateNewScheduledMessage();
1704 		session().data().scheduledMessages().apply(d);
1705 	} break;
1706 
1707 	case mtpc_updateDeleteScheduledMessages: {
1708 		const auto &d = update.c_updateDeleteScheduledMessages();
1709 		session().data().scheduledMessages().apply(d);
1710 	} break;
1711 
1712 	case mtpc_updateWebPage: {
1713 		auto &d = update.c_updateWebPage();
1714 
1715 		// Update web page anyway.
1716 		session().data().processWebpage(d.vwebpage());
1717 		session().data().sendWebPageGamePollNotifications();
1718 
1719 		updateAndApply(d.vpts().v, d.vpts_count().v, update);
1720 	} break;
1721 
1722 	case mtpc_updateChannelWebPage: {
1723 		auto &d = update.c_updateChannelWebPage();
1724 
1725 		// Update web page anyway.
1726 		session().data().processWebpage(d.vwebpage());
1727 		session().data().sendWebPageGamePollNotifications();
1728 
1729 		auto channel = session().data().channelLoaded(d.vchannel_id());
1730 		if (channel && !_handlingChannelDifference) {
1731 			if (channel->ptsRequesting()) { // skip global updates while getting channel difference
1732 				return;
1733 			} else {
1734 				channel->ptsUpdateAndApply(d.vpts().v, d.vpts_count().v, update);
1735 			}
1736 		} else {
1737 			applyUpdateNoPtsCheck(update);
1738 		}
1739 	} break;
1740 
1741 	case mtpc_updateMessagePoll: {
1742 		session().data().applyUpdate(update.c_updateMessagePoll());
1743 	} break;
1744 
1745 	case mtpc_updateUserTyping: {
1746 		auto &d = update.c_updateUserTyping();
1747 		handleSendActionUpdate(
1748 			peerFromUser(d.vuser_id()),
1749 			0,
1750 			peerFromUser(d.vuser_id()),
1751 			d.vaction());
1752 	} break;
1753 
1754 	case mtpc_updateChatUserTyping: {
1755 		auto &d = update.c_updateChatUserTyping();
1756 		handleSendActionUpdate(
1757 			peerFromChat(d.vchat_id()),
1758 			0,
1759 			peerFromMTP(d.vfrom_id()),
1760 			d.vaction());
1761 	} break;
1762 
1763 	case mtpc_updateChannelUserTyping: {
1764 		const auto &d = update.c_updateChannelUserTyping();
1765 		handleSendActionUpdate(
1766 			peerFromChannel(d.vchannel_id()),
1767 			d.vtop_msg_id().value_or_empty(),
1768 			peerFromMTP(d.vfrom_id()),
1769 			d.vaction());
1770 	} break;
1771 
1772 	case mtpc_updateChatParticipants: {
1773 		session().data().applyUpdate(update.c_updateChatParticipants());
1774 	} break;
1775 
1776 	case mtpc_updateChatParticipantAdd: {
1777 		session().data().applyUpdate(update.c_updateChatParticipantAdd());
1778 	} break;
1779 
1780 	case mtpc_updateChatParticipantDelete: {
1781 		session().data().applyUpdate(update.c_updateChatParticipantDelete());
1782 	} break;
1783 
1784 	case mtpc_updateChatParticipantAdmin: {
1785 		session().data().applyUpdate(update.c_updateChatParticipantAdmin());
1786 	} break;
1787 
1788 	case mtpc_updateChatDefaultBannedRights: {
1789 		session().data().applyUpdate(update.c_updateChatDefaultBannedRights());
1790 	} break;
1791 
1792 	case mtpc_updateUserStatus: {
1793 		auto &d = update.c_updateUserStatus();
1794 		if (auto user = session().data().userLoaded(d.vuser_id())) {
1795 			switch (d.vstatus().type()) {
1796 			case mtpc_userStatusEmpty: user->onlineTill = 0; break;
1797 			case mtpc_userStatusRecently:
1798 				if (user->onlineTill > -10) { // don't modify pseudo-online
1799 					user->onlineTill = -2;
1800 				}
1801 			break;
1802 			case mtpc_userStatusLastWeek: user->onlineTill = -3; break;
1803 			case mtpc_userStatusLastMonth: user->onlineTill = -4; break;
1804 			case mtpc_userStatusOffline: user->onlineTill = d.vstatus().c_userStatusOffline().vwas_online().v; break;
1805 			case mtpc_userStatusOnline: user->onlineTill = d.vstatus().c_userStatusOnline().vexpires().v; break;
1806 			}
1807 			session().changes().peerUpdated(
1808 				user,
1809 				Data::PeerUpdate::Flag::OnlineStatus);
1810 		}
1811 		if (UserId(d.vuser_id()) == session().userId()) {
1812 			if (d.vstatus().type() == mtpc_userStatusOffline
1813 				|| d.vstatus().type() == mtpc_userStatusEmpty) {
1814 				updateOnline(Core::App().lastNonIdleTime(), true);
1815 				if (d.vstatus().type() == mtpc_userStatusOffline) {
1816 					cSetOtherOnline(
1817 						d.vstatus().c_userStatusOffline().vwas_online().v);
1818 				}
1819 			} else if (d.vstatus().type() == mtpc_userStatusOnline) {
1820 				cSetOtherOnline(
1821 					d.vstatus().c_userStatusOnline().vexpires().v);
1822 			}
1823 		}
1824 	} break;
1825 
1826 	case mtpc_updateUserName: {
1827 		auto &d = update.c_updateUserName();
1828 		if (auto user = session().data().userLoaded(d.vuser_id())) {
1829 			if (!user->isContact()) {
1830 				user->setName(
1831 					TextUtilities::SingleLine(qs(d.vfirst_name())),
1832 					TextUtilities::SingleLine(qs(d.vlast_name())),
1833 					user->nameOrPhone,
1834 					TextUtilities::SingleLine(qs(d.vusername())));
1835 			} else {
1836 				user->setName(
1837 					TextUtilities::SingleLine(user->firstName),
1838 					TextUtilities::SingleLine(user->lastName),
1839 					user->nameOrPhone,
1840 					TextUtilities::SingleLine(qs(d.vusername())));
1841 			}
1842 		}
1843 	} break;
1844 
1845 	case mtpc_updateUserPhoto: {
1846 		auto &d = update.c_updateUserPhoto();
1847 		if (auto user = session().data().userLoaded(d.vuser_id())) {
1848 			user->setPhoto(d.vphoto());
1849 			user->loadUserpic();
1850 			// After that update we don't have enough information to
1851 			// create a 'photo' with all necessary fields. So if
1852 			// we receive second such update we end up with a 'photo_id'
1853 			// in user_photos list without a loaded 'photo'.
1854 			// It fails to show in media overview if you try to open it.
1855 			//
1856 			//if (mtpIsTrue(d.vprevious()) || !user->userpicPhotoId()) {
1857 				session().storage().remove(Storage::UserPhotosRemoveAfter(
1858 					peerToUser(user->id),
1859 					user->userpicPhotoId()));
1860 			//} else {
1861 			//	session().storage().add(Storage::UserPhotosAddNew(
1862 			//		peerToUser(user->id),
1863 			//		user->userpicPhotoId()));
1864 			//}
1865 		}
1866 	} break;
1867 
1868 	case mtpc_updatePeerSettings: {
1869 		const auto &d = update.c_updatePeerSettings();
1870 		const auto peerId = peerFromMTP(d.vpeer());
1871 		if (const auto peer = session().data().peerLoaded(peerId)) {
1872 			peer->setSettings(d.vsettings());
1873 		}
1874 	} break;
1875 
1876 	case mtpc_updateNotifySettings: {
1877 		auto &d = update.c_updateNotifySettings();
1878 		session().data().applyNotifySetting(d.vpeer(), d.vnotify_settings());
1879 	} break;
1880 
1881 	case mtpc_updateDcOptions: {
1882 		auto &d = update.c_updateDcOptions();
1883 		session().mtp().dcOptions().addFromList(d.vdc_options());
1884 	} break;
1885 
1886 	case mtpc_updateConfig: {
1887 		session().mtp().requestConfig();
1888 	} break;
1889 
1890 	case mtpc_updateUserPhone: {
1891 		const auto &d = update.c_updateUserPhone();
1892 		if (const auto user = session().data().userLoaded(d.vuser_id())) {
1893 			const auto newPhone = qs(d.vphone());
1894 			if (newPhone != user->phone()) {
1895 				user->setPhone(newPhone);
1896 				user->setName(
1897 					user->firstName,
1898 					user->lastName,
1899 					((user->isContact()
1900 						|| user->isServiceUser()
1901 						|| user->isSelf()
1902 						|| user->phone().isEmpty())
1903 						? QString()
1904 						: Ui::FormatPhone(user->phone())),
1905 					user->username);
1906 
1907 				session().changes().peerUpdated(
1908 					user,
1909 					Data::PeerUpdate::Flag::PhoneNumber);
1910 			}
1911 		}
1912 	} break;
1913 
1914 	case mtpc_updatePeerHistoryTTL: {
1915 		const auto &d = update.c_updatePeerHistoryTTL();
1916 		const auto peerId = peerFromMTP(d.vpeer());
1917 		if (const auto peer = session().data().peerLoaded(peerId)) {
1918 			peer->setMessagesTTL(d.vttl_period().value_or_empty());
1919 		}
1920 	} break;
1921 
1922 	case mtpc_updateNewEncryptedMessage: {
1923 	} break;
1924 
1925 	case mtpc_updateEncryptedChatTyping: {
1926 	} break;
1927 
1928 	case mtpc_updateEncryption: {
1929 	} break;
1930 
1931 	case mtpc_updateEncryptedMessagesRead: {
1932 	} break;
1933 
1934 	case mtpc_updatePhoneCall:
1935 	case mtpc_updatePhoneCallSignalingData:
1936 	case mtpc_updateGroupCallParticipants:
1937 	case mtpc_updateGroupCallConnection:
1938 	case mtpc_updateGroupCall: {
1939 		Core::App().calls().handleUpdate(&session(), update);
1940 	} break;
1941 
1942 	case mtpc_updatePeerBlocked: {
1943 		const auto &d = update.c_updatePeerBlocked();
1944 		if (const auto peer = session().data().peerLoaded(peerFromMTP(d.vpeer_id()))) {
1945 			peer->setIsBlocked(mtpIsTrue(d.vblocked()));
1946 		}
1947 	} break;
1948 
1949 	case mtpc_updateBotCommands: {
1950 		const auto &d = update.c_updateBotCommands();
1951 		if (const auto peer = session().data().peerLoaded(peerFromMTP(d.vpeer()))) {
1952 			const auto botId = UserId(d.vbot_id().v);
1953 			if (const auto user = peer->asUser()) {
1954 				if (user->isBot() && user->id == peerFromUser(botId)) {
1955 					if (Data::UpdateBotCommands(user->botInfo->commands, d.vcommands())) {
1956 						session().data().botCommandsChanged(user);
1957 					}
1958 				}
1959 			} else if (const auto chat = peer->asChat()) {
1960 				chat->setBotCommands(botId, d.vcommands());
1961 			} else if (const auto megagroup = peer->asMegagroup()) {
1962 				if (megagroup->mgInfo->updateBotCommands(botId, d.vcommands())) {
1963 					session().data().botCommandsChanged(megagroup);
1964 				}
1965 			}
1966 		}
1967 	} break;
1968 
1969 	case mtpc_updatePendingJoinRequests: {
1970 		const auto &d = update.c_updatePendingJoinRequests();
1971 		if (const auto peer = session().data().peerLoaded(peerFromMTP(d.vpeer()))) {
1972 			const auto count = d.vrequests_pending().v;
1973 			const auto &requesters = d.vrecent_requesters().v;
1974 			if (const auto chat = peer->asChat()) {
1975 				chat->setPendingRequestsCount(count, requesters);
1976 			} else if (const auto channel = peer->asChannel()) {
1977 				channel->setPendingRequestsCount(count, requesters);
1978 			}
1979 		}
1980 	} break;
1981 
1982 	case mtpc_updateServiceNotification: {
1983 		const auto &d = update.c_updateServiceNotification();
1984 		const auto text = TextWithEntities {
1985 			qs(d.vmessage()),
1986 			Api::EntitiesFromMTP(&session(), d.ventities().v)
1987 		};
1988 		if (IsForceLogoutNotification(d)) {
1989 			Core::App().forceLogOut(&session().account(), text);
1990 		} else if (d.is_popup()) {
1991 			const auto &windows = session().windows();
1992 			if (!windows.empty()) {
1993 				windows.front()->window().show(Box<Ui::InformBox>(text));
1994 			}
1995 		} else {
1996 			session().data().serviceNotification(text, d.vmedia());
1997 			session().api().authorizations().reload();
1998 		}
1999 	} break;
2000 
2001 	case mtpc_updatePrivacy: {
2002 		auto &d = update.c_updatePrivacy();
2003 		const auto allChatsLoaded = [&](const MTPVector<MTPlong> &ids) {
2004 			for (const auto &chatId : ids.v) {
2005 				if (!session().data().chatLoaded(chatId)
2006 					&& !session().data().channelLoaded(chatId)) {
2007 					return false;
2008 				}
2009 			}
2010 			return true;
2011 		};
2012 		const auto allLoaded = [&] {
2013 			for (const auto &rule : d.vrules().v) {
2014 				const auto loaded = rule.match([&](
2015 					const MTPDprivacyValueAllowChatParticipants & data) {
2016 					return allChatsLoaded(data.vchats());
2017 				}, [&](const MTPDprivacyValueDisallowChatParticipants & data) {
2018 					return allChatsLoaded(data.vchats());
2019 				}, [](auto &&) { return true; });
2020 				if (!loaded) {
2021 					return false;
2022 				}
2023 			}
2024 			return true;
2025 		};
2026 		session().api().userPrivacy().apply(
2027 			d.vkey().type(),
2028 			d.vrules(),
2029 			allLoaded());
2030 	} break;
2031 
2032 	case mtpc_updatePinnedDialogs: {
2033 		const auto &d = update.c_updatePinnedDialogs();
2034 		const auto folderId = d.vfolder_id().value_or_empty();
2035 		const auto loaded = !folderId
2036 			|| (session().data().folderLoaded(folderId) != nullptr);
2037 		const auto folder = folderId
2038 			? session().data().folder(folderId).get()
2039 			: nullptr;
2040 		const auto done = [&] {
2041 			const auto list = d.vorder();
2042 			if (!list) {
2043 				return false;
2044 			}
2045 			const auto &order = list->v;
2046 			const auto notLoaded = [&](const MTPDialogPeer &peer) {
2047 				return peer.match([&](const MTPDdialogPeer &data) {
2048 					return !session().data().historyLoaded(
2049 						peerFromMTP(data.vpeer()));
2050 				}, [&](const MTPDdialogPeerFolder &data) {
2051 					if (folderId) {
2052 						LOG(("API Error: "
2053 							"updatePinnedDialogs has nested folders."));
2054 						return true;
2055 					}
2056 					return !session().data().folderLoaded(data.vfolder_id().v);
2057 				});
2058 			};
2059 			if (!ranges::none_of(order, notLoaded)) {
2060 				return false;
2061 			}
2062 			session().data().applyPinnedChats(folder, order);
2063 			return true;
2064 		}();
2065 		if (!done) {
2066 			session().api().requestPinnedDialogs(folder);
2067 		}
2068 		if (!loaded) {
2069 			session().data().histories().requestDialogEntry(folder);
2070 		}
2071 	} break;
2072 
2073 	case mtpc_updateDialogPinned: {
2074 		const auto &d = update.c_updateDialogPinned();
2075 		const auto folderId = d.vfolder_id().value_or_empty();
2076 		const auto folder = folderId
2077 			? session().data().folder(folderId).get()
2078 			: nullptr;
2079 		const auto done = d.vpeer().match([&](const MTPDdialogPeer &data) {
2080 			const auto id = peerFromMTP(data.vpeer());
2081 			if (const auto history = session().data().historyLoaded(id)) {
2082 				history->applyPinnedUpdate(d);
2083 				return true;
2084 			}
2085 			DEBUG_LOG(("API Error: "
2086 				"pinned chat not loaded for peer %1, folder: %2"
2087 				).arg(id.value
2088 				).arg(folderId
2089 				));
2090 			return false;
2091 		}, [&](const MTPDdialogPeerFolder &data) {
2092 			if (folderId != 0) {
2093 				DEBUG_LOG(("API Error: Nested folders updateDialogPinned."));
2094 				return false;
2095 			}
2096 			const auto id = data.vfolder_id().v;
2097 			if (const auto folder = session().data().folderLoaded(id)) {
2098 				folder->applyPinnedUpdate(d);
2099 				return true;
2100 			}
2101 			DEBUG_LOG(("API Error: "
2102 				"pinned folder not loaded for folderId %1, folder: %2"
2103 				).arg(id
2104 				).arg(folderId
2105 				));
2106 			return false;
2107 		});
2108 		if (!done) {
2109 			session().api().requestPinnedDialogs(folder);
2110 		}
2111 	} break;
2112 
2113 	case mtpc_updateChannel: {
2114 		auto &d = update.c_updateChannel();
2115 		if (const auto channel = session().data().channelLoaded(d.vchannel_id())) {
2116 			channel->inviter = UserId(0);
2117 			channel->inviteViaRequest = false;
2118 			if (channel->amIn()) {
2119 				if (channel->isMegagroup()
2120 					&& !channel->amCreator()
2121 					&& !channel->hasAdminRights()) {
2122 					channel->updateFullForced();
2123 				}
2124 				const auto history = channel->owner().history(channel);
2125 				history->requestChatListMessage();
2126 				if (!history->unreadCountKnown()) {
2127 					history->owner().histories().requestDialogEntry(history);
2128 				}
2129 				if (!channel->amCreator()) {
2130 					session().api().requestSelfParticipant(channel);
2131 				}
2132 			}
2133 		}
2134 	} break;
2135 
2136 	case mtpc_updateChannelTooLong: {
2137 		const auto &d = update.c_updateChannelTooLong();
2138 		if (const auto channel = session().data().channelLoaded(d.vchannel_id())) {
2139 			const auto pts = d.vpts();
2140 			if (!pts || channel->pts() < pts->v) {
2141 				getChannelDifference(channel);
2142 			}
2143 		}
2144 	} break;
2145 
2146 	case mtpc_updateChannelMessageViews: {
2147 		const auto &d = update.c_updateChannelMessageViews();
2148 		if (const auto item = session().data().message(d.vchannel_id().v, d.vid().v)) {
2149 			item->setViewsCount(d.vviews().v);
2150 		}
2151 	} break;
2152 
2153 	case mtpc_updateChannelMessageForwards: {
2154 		const auto &d = update.c_updateChannelMessageForwards();
2155 		if (const auto item = session().data().message(d.vchannel_id().v, d.vid().v)) {
2156 			item->setForwardsCount(d.vforwards().v);
2157 		}
2158 	} break;
2159 
2160 	case mtpc_updateReadChannelDiscussionInbox: {
2161 		const auto &d = update.c_updateReadChannelDiscussionInbox();
2162 		const auto channelId = d.vchannel_id().v;
2163 		const auto msgId = d.vtop_msg_id().v;
2164 		const auto readTillId = d.vread_max_id().v;
2165 		const auto item = session().data().message(channelId, msgId);
2166 		const auto unreadCount = item
2167 			? session().data().countUnreadRepliesLocally(item, readTillId)
2168 			: std::nullopt;
2169 		if (item) {
2170 			item->setRepliesInboxReadTill(readTillId, unreadCount);
2171 			if (const auto post = item->lookupDiscussionPostOriginal()) {
2172 				post->setRepliesInboxReadTill(readTillId, unreadCount);
2173 			}
2174 		}
2175 		if (const auto broadcastId = d.vbroadcast_id()) {
2176 			if (const auto post = session().data().message(
2177 					broadcastId->v,
2178 					d.vbroadcast_post()->v)) {
2179 				post->setRepliesInboxReadTill(readTillId, unreadCount);
2180 			}
2181 		}
2182 	} break;
2183 
2184 	case mtpc_updateReadChannelDiscussionOutbox: {
2185 		const auto &d = update.c_updateReadChannelDiscussionOutbox();
2186 		const auto channelId = d.vchannel_id().v;
2187 		const auto msgId = d.vtop_msg_id().v;
2188 		const auto readTillId = d.vread_max_id().v;
2189 		const auto item = session().data().message(channelId, msgId);
2190 		if (item) {
2191 			item->setRepliesOutboxReadTill(readTillId);
2192 			if (const auto post = item->lookupDiscussionPostOriginal()) {
2193 				post->setRepliesOutboxReadTill(readTillId);
2194 			}
2195 		}
2196 	} break;
2197 
2198 	case mtpc_updateChannelAvailableMessages: {
2199 		auto &d = update.c_updateChannelAvailableMessages();
2200 		if (const auto channel = session().data().channelLoaded(d.vchannel_id())) {
2201 			channel->setAvailableMinId(d.vavailable_min_id().v);
2202 			if (const auto history = session().data().historyLoaded(channel)) {
2203 				history->clearUpTill(d.vavailable_min_id().v);
2204 			}
2205 		}
2206 	} break;
2207 
2208 	// Pinned message.
2209 	case mtpc_updatePinnedMessages: {
2210 		const auto &d = update.c_updatePinnedMessages();
2211 		updateAndApply(d.vpts().v, d.vpts_count().v, update);
2212 	} break;
2213 
2214 	////// Cloud sticker sets
2215 	case mtpc_updateNewStickerSet: {
2216 		const auto &d = update.c_updateNewStickerSet();
2217 		session().data().stickers().newSetReceived(d.vstickerset());
2218 	} break;
2219 
2220 	case mtpc_updateStickerSetsOrder: {
2221 		auto &d = update.c_updateStickerSetsOrder();
2222 		auto &stickers = session().data().stickers();
2223 		const auto isMasks = d.is_masks();
2224 		const auto &order = d.vorder().v;
2225 		const auto &sets = stickers.sets();
2226 		Data::StickersSetsOrder result;
2227 		for (const auto &item : order) {
2228 			if (sets.find(item.v) == sets.cend()) {
2229 				break;
2230 			}
2231 			result.push_back(item.v);
2232 		}
2233 		const auto localSize = isMasks
2234 			? stickers.maskSetsOrder().size()
2235 			: stickers.setsOrder().size();
2236 		if ((result.size() != localSize) || (result.size() != order.size())) {
2237 			if (isMasks) {
2238 				stickers.setLastMasksUpdate(0);
2239 				session().api().updateMasks();
2240 			} else {
2241 				stickers.setLastUpdate(0);
2242 				session().api().updateStickers();
2243 			}
2244 		} else {
2245 			if (isMasks) {
2246 				stickers.maskSetsOrderRef() = std::move(result);
2247 				session().local().writeInstalledMasks();
2248 			} else {
2249 				stickers.setsOrderRef() = std::move(result);
2250 				session().local().writeInstalledStickers();
2251 			}
2252 			stickers.notifyUpdated();
2253 		}
2254 	} break;
2255 
2256 	case mtpc_updateStickerSets: {
2257 		// Can't determine is it masks or stickers, so update both.
2258 		session().data().stickers().setLastUpdate(0);
2259 		session().api().updateStickers();
2260 		session().data().stickers().setLastMasksUpdate(0);
2261 		session().api().updateMasks();
2262 	} break;
2263 
2264 	case mtpc_updateRecentStickers: {
2265 		session().data().stickers().setLastRecentUpdate(0);
2266 		session().api().updateStickers();
2267 	} break;
2268 
2269 	case mtpc_updateFavedStickers: {
2270 		session().data().stickers().setLastFavedUpdate(0);
2271 		session().api().updateStickers();
2272 	} break;
2273 
2274 	case mtpc_updateReadFeaturedStickers: {
2275 		// We read some of the featured stickers, perhaps not all of them.
2276 		// Here we don't know what featured sticker sets were read, so we
2277 		// request all of them once again.
2278 		session().data().stickers().setLastFeaturedUpdate(0);
2279 		session().api().updateStickers();
2280 	} break;
2281 
2282 	////// Cloud saved GIFs
2283 	case mtpc_updateSavedGifs: {
2284 		session().data().stickers().setLastSavedGifsUpdate(0);
2285 		session().api().updateStickers();
2286 	} break;
2287 
2288 	////// Cloud drafts
2289 	case mtpc_updateDraftMessage: {
2290 		const auto &data = update.c_updateDraftMessage();
2291 		const auto peerId = peerFromMTP(data.vpeer());
2292 		data.vdraft().match([&](const MTPDdraftMessage &data) {
2293 			Data::ApplyPeerCloudDraft(&session(), peerId, data);
2294 		}, [&](const MTPDdraftMessageEmpty &data) {
2295 			Data::ClearPeerCloudDraft(
2296 				&session(),
2297 				peerId,
2298 				data.vdate().value_or_empty());
2299 		});
2300 	} break;
2301 
2302 	////// Cloud langpacks
2303 	case mtpc_updateLangPack: {
2304 		const auto &data = update.c_updateLangPack();
2305 		Lang::CurrentCloudManager().applyLangPackDifference(data.vdifference());
2306 	} break;
2307 
2308 	case mtpc_updateLangPackTooLong: {
2309 		const auto &data = update.c_updateLangPackTooLong();
2310 		const auto code = qs(data.vlang_code());
2311 		if (!code.isEmpty()) {
2312 			Lang::CurrentCloudManager().requestLangPackDifference(code);
2313 		}
2314 	} break;
2315 
2316 	////// Cloud themes
2317 	case mtpc_updateTheme: {
2318 		const auto &data = update.c_updateTheme();
2319 		session().data().cloudThemes().applyUpdate(data.vtheme());
2320 	} break;
2321 
2322 	}
2323 }
2324 
2325 } // namespace Api
2326