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 "data/data_chat.h"
9 
10 #include "data/data_user.h"
11 #include "data/data_channel.h"
12 #include "data/data_session.h"
13 #include "data/data_changes.h"
14 #include "data/data_group_call.h"
15 #include "history/history.h"
16 #include "main/main_session.h"
17 #include "apiwrap.h"
18 #include "api/api_invite_links.h"
19 
20 namespace {
21 
22 using UpdateFlag = Data::PeerUpdate::Flag;
23 
24 } // namespace
25 
ChatData(not_null<Data::Session * > owner,PeerId id)26 ChatData::ChatData(not_null<Data::Session*> owner, PeerId id)
27 : PeerData(owner, id)
28 , inputChat(MTP_long(peerToChat(id).bare)) {
29 	_flags.changes(
30 	) | rpl::start_with_next([=](const Flags::Change &change) {
31 		if (change.diff & ChatDataFlag::CallNotEmpty) {
32 			if (const auto history = this->owner().historyLoaded(this)) {
33 				history->updateChatListEntry();
34 			}
35 		}
36 	}, _lifetime);
37 }
38 
setPhoto(const MTPChatPhoto & photo)39 void ChatData::setPhoto(const MTPChatPhoto &photo) {
40 	photo.match([&](const MTPDchatPhoto &data) {
41 		updateUserpic(data.vphoto_id().v, data.vdc_id().v);
42 	}, [&](const MTPDchatPhotoEmpty &) {
43 		clearUserpic();
44 	});
45 }
46 
defaultAdminRights(not_null<UserData * > user)47 ChatAdminRightsInfo ChatData::defaultAdminRights(not_null<UserData*> user) {
48 	const auto isCreator = (creator == peerToUser(user->id))
49 		|| (user->isSelf() && amCreator());
50 	using Flag = AdminRight;
51 	return ChatAdminRightsInfo(Flag::Other
52 		| Flag::ChangeInfo
53 		| Flag::DeleteMessages
54 		| Flag::BanUsers
55 		| Flag::InviteUsers
56 		| Flag::PinMessages
57 		| Flag::ManageCall
58 		| (isCreator ? Flag::AddAdmins : Flag(0)));
59 }
60 
canWrite() const61 bool ChatData::canWrite() const {
62 	// Duplicated in Data::CanWriteValue().
63 	return amIn() && !amRestricted(Restriction::SendMessages);
64 }
65 
canEditInformation() const66 bool ChatData::canEditInformation() const {
67 	return amIn() && !amRestricted(Restriction::ChangeInfo);
68 }
69 
canEditPermissions() const70 bool ChatData::canEditPermissions() const {
71 	return amIn()
72 		&& (amCreator() || (adminRights() & AdminRight::BanUsers));
73 }
74 
canEditUsername() const75 bool ChatData::canEditUsername() const {
76 	return amCreator()
77 		&& (flags() & ChatDataFlag::CanSetUsername);
78 }
79 
canEditPreHistoryHidden() const80 bool ChatData::canEditPreHistoryHidden() const {
81 	return amCreator();
82 }
83 
canDeleteMessages() const84 bool ChatData::canDeleteMessages() const {
85 	return amCreator()
86 		|| (adminRights() & AdminRight::DeleteMessages);
87 }
88 
canAddMembers() const89 bool ChatData::canAddMembers() const {
90 	return amIn() && !amRestricted(Restriction::InviteUsers);
91 }
92 
canSendPolls() const93 bool ChatData::canSendPolls() const {
94 	return amIn() && !amRestricted(Restriction::SendPolls);
95 }
96 
canAddAdmins() const97 bool ChatData::canAddAdmins() const {
98 	return amIn() && amCreator();
99 }
100 
canBanMembers() const101 bool ChatData::canBanMembers() const {
102 	return amCreator()
103 		|| (adminRights() & AdminRight::BanUsers);
104 }
105 
anyoneCanAddMembers() const106 bool ChatData::anyoneCanAddMembers() const {
107 	return !(defaultRestrictions() & Restriction::InviteUsers);
108 }
109 
setName(const QString & newName)110 void ChatData::setName(const QString &newName) {
111 	updateNameDelayed(newName.isEmpty() ? name : newName, QString(), QString());
112 }
113 
applyEditAdmin(not_null<UserData * > user,bool isAdmin)114 void ChatData::applyEditAdmin(not_null<UserData*> user, bool isAdmin) {
115 	if (isAdmin) {
116 		admins.emplace(user);
117 	} else {
118 		admins.remove(user);
119 	}
120 	session().changes().peerUpdated(this, UpdateFlag::Admins);
121 }
122 
invalidateParticipants()123 void ChatData::invalidateParticipants() {
124 	participants.clear();
125 	admins.clear();
126 	setAdminRights(ChatAdminRights());
127 	//setDefaultRestrictions(ChatRestrictions());
128 	invitedByMe.clear();
129 	botStatus = 0;
130 	session().changes().peerUpdated(
131 		this,
132 		UpdateFlag::Members | UpdateFlag::Admins);
133 }
134 
setInviteLink(const QString & newInviteLink)135 void ChatData::setInviteLink(const QString &newInviteLink) {
136 	_inviteLink = newInviteLink;
137 }
138 
canHaveInviteLink() const139 bool ChatData::canHaveInviteLink() const {
140 	return amCreator()
141 		|| (adminRights() & AdminRight::InviteUsers);
142 }
143 
setAdminRights(ChatAdminRights rights)144 void ChatData::setAdminRights(ChatAdminRights rights) {
145 	if (rights == adminRights()) {
146 		return;
147 	}
148 	_adminRights.set(rights);
149 	if (!canHaveInviteLink()) {
150 		setPendingRequestsCount(0, std::vector<UserId>{});
151 	}
152 	session().changes().peerUpdated(
153 		this,
154 		UpdateFlag::Rights | UpdateFlag::Admins | UpdateFlag::BannedUsers);
155 }
156 
setDefaultRestrictions(ChatRestrictions rights)157 void ChatData::setDefaultRestrictions(ChatRestrictions rights) {
158 	if (rights == defaultRestrictions()) {
159 		return;
160 	}
161 	_defaultRestrictions.set(rights);
162 	session().changes().peerUpdated(this, UpdateFlag::Rights);
163 }
164 
refreshBotStatus()165 void ChatData::refreshBotStatus() {
166 	if (participants.empty()) {
167 		botStatus = 0;
168 	} else {
169 		const auto bot = ranges::none_of(participants, &UserData::isBot);
170 		botStatus = bot ? -1 : 2;
171 	}
172 }
173 
applyUpdateVersion(int version)174 auto ChatData::applyUpdateVersion(int version) -> UpdateStatus {
175 	if (_version > version) {
176 		return UpdateStatus::TooOld;
177 	} else if (_version + 1 < version) {
178 		invalidateParticipants();
179 		session().api().requestFullPeer(this);
180 		return UpdateStatus::Skipped;
181 	}
182 	setVersion(version);
183 	return UpdateStatus::Good;
184 }
185 
getMigrateToChannel() const186 ChannelData *ChatData::getMigrateToChannel() const {
187 	return _migratedTo;
188 }
189 
setMigrateToChannel(ChannelData * channel)190 void ChatData::setMigrateToChannel(ChannelData *channel) {
191 	if (_migratedTo != channel) {
192 		_migratedTo = channel;
193 		if (channel->amIn()) {
194 			session().changes().peerUpdated(this, UpdateFlag::Migration);
195 		}
196 	}
197 }
198 
setGroupCall(const MTPInputGroupCall & call,TimeId scheduleDate)199 void ChatData::setGroupCall(
200 		const MTPInputGroupCall &call,
201 		TimeId scheduleDate) {
202 	if (migrateTo()) {
203 		return;
204 	}
205 	call.match([&](const MTPDinputGroupCall &data) {
206 		if (_call && _call->id() == data.vid().v) {
207 			return;
208 		} else if (!_call && !data.vid().v) {
209 			return;
210 		} else if (!data.vid().v) {
211 			clearGroupCall();
212 			return;
213 		}
214 		const auto hasCall = (_call != nullptr);
215 		if (hasCall) {
216 			owner().unregisterGroupCall(_call.get());
217 		}
218 		_call = std::make_unique<Data::GroupCall>(
219 			this,
220 			data.vid().v,
221 			data.vaccess_hash().v,
222 			scheduleDate);
223 		owner().registerGroupCall(_call.get());
224 		session().changes().peerUpdated(this, UpdateFlag::GroupCall);
225 		addFlags(ChatDataFlag::CallActive);
226 	});
227 }
228 
clearGroupCall()229 void ChatData::clearGroupCall() {
230 	if (!_call) {
231 		return;
232 	} else if (const auto group = migrateTo(); group && !group->groupCall()) {
233 		group->migrateCall(base::take(_call));
234 	} else {
235 		owner().unregisterGroupCall(_call.get());
236 		_call = nullptr;
237 	}
238 	session().changes().peerUpdated(this, UpdateFlag::GroupCall);
239 	removeFlags(ChatDataFlag::CallActive | ChatDataFlag::CallNotEmpty);
240 }
241 
setGroupCallDefaultJoinAs(PeerId peerId)242 void ChatData::setGroupCallDefaultJoinAs(PeerId peerId) {
243 	_callDefaultJoinAs = peerId;
244 }
245 
groupCallDefaultJoinAs() const246 PeerId ChatData::groupCallDefaultJoinAs() const {
247 	return _callDefaultJoinAs;
248 }
249 
setBotCommands(const MTPVector<MTPBotInfo> & data)250 void ChatData::setBotCommands(const MTPVector<MTPBotInfo> &data) {
251 	if (Data::UpdateBotCommands(_botCommands, data)) {
252 		owner().botCommandsChanged(this);
253 	}
254 }
255 
setBotCommands(UserId botId,const MTPVector<MTPBotCommand> & data)256 void ChatData::setBotCommands(
257 		UserId botId,
258 		const MTPVector<MTPBotCommand> &data) {
259 	if (Data::UpdateBotCommands(_botCommands, botId, data)) {
260 		owner().botCommandsChanged(this);
261 	}
262 }
263 
setPendingRequestsCount(int count,const QVector<MTPlong> & recentRequesters)264 void ChatData::setPendingRequestsCount(
265 		int count,
266 		const QVector<MTPlong> &recentRequesters) {
267 	setPendingRequestsCount(count, ranges::views::all(
268 		recentRequesters
269 	) | ranges::views::transform([&](const MTPlong &value) {
270 		return UserId(value);
271 	}) | ranges::to_vector);
272 }
273 
setPendingRequestsCount(int count,std::vector<UserId> recentRequesters)274 void ChatData::setPendingRequestsCount(
275 		int count,
276 		std::vector<UserId> recentRequesters) {
277 	if (_pendingRequestsCount != count
278 		|| _recentRequesters != recentRequesters) {
279 		_pendingRequestsCount = count;
280 		_recentRequesters = std::move(recentRequesters);
281 		session().changes().peerUpdated(this, UpdateFlag::PendingRequests);
282 	}
283 }
284 
285 namespace Data {
286 
ApplyChatUpdate(not_null<ChatData * > chat,const MTPDupdateChatParticipants & update)287 void ApplyChatUpdate(
288 		not_null<ChatData*> chat,
289 		const MTPDupdateChatParticipants &update) {
290 	ApplyChatUpdate(chat, update.vparticipants());
291 }
292 
ApplyChatUpdate(not_null<ChatData * > chat,const MTPDupdateChatParticipantAdd & update)293 void ApplyChatUpdate(
294 		not_null<ChatData*> chat,
295 		const MTPDupdateChatParticipantAdd &update) {
296 	if (chat->applyUpdateVersion(update.vversion().v)
297 		!= ChatData::UpdateStatus::Good) {
298 		return;
299 	} else if (chat->count < 0) {
300 		return;
301 	}
302 	const auto user = chat->owner().userLoaded(update.vuser_id().v);
303 	const auto session = &chat->session();
304 	if (!user
305 		|| (!chat->participants.empty()
306 			&& chat->participants.contains(user))) {
307 		chat->invalidateParticipants();
308 		++chat->count;
309 		return;
310 	}
311 	if (chat->participants.empty()) {
312 		if (chat->count > 0) { // If the count is known.
313 			++chat->count;
314 		}
315 		chat->botStatus = 0;
316 	} else {
317 		chat->participants.emplace(user);
318 		if (UserId(update.vinviter_id()) == session->userId()) {
319 			chat->invitedByMe.insert(user);
320 		} else {
321 			chat->invitedByMe.remove(user);
322 		}
323 		++chat->count;
324 		if (user->isBot()) {
325 			chat->botStatus = 2;
326 			if (!user->botInfo->inited) {
327 				session->api().requestFullPeer(user);
328 			}
329 		}
330 	}
331 	session->changes().peerUpdated(chat, UpdateFlag::Members);
332 }
333 
ApplyChatUpdate(not_null<ChatData * > chat,const MTPDupdateChatParticipantDelete & update)334 void ApplyChatUpdate(
335 		not_null<ChatData*> chat,
336 		const MTPDupdateChatParticipantDelete &update) {
337 	if (chat->applyUpdateVersion(update.vversion().v)
338 		!= ChatData::UpdateStatus::Good) {
339 		return;
340 	} else if (chat->count <= 0) {
341 		return;
342 	}
343 	const auto user = chat->owner().userLoaded(update.vuser_id().v);
344 	if (!user
345 		|| (!chat->participants.empty()
346 			&& !chat->participants.contains(user))) {
347 		chat->invalidateParticipants();
348 		--chat->count;
349 		return;
350 	}
351 	if (chat->participants.empty()) {
352 		if (chat->count > 0) {
353 			chat->count--;
354 		}
355 		chat->botStatus = 0;
356 	} else {
357 		chat->participants.erase(user);
358 		chat->count--;
359 		chat->invitedByMe.remove(user);
360 		chat->admins.remove(user);
361 		if (user->isSelf()) {
362 			chat->setAdminRights(ChatAdminRights());
363 		}
364 		if (const auto history = chat->owner().historyLoaded(chat)) {
365 			if (history->lastKeyboardFrom == user->id) {
366 				history->clearLastKeyboard();
367 			}
368 		}
369 		if (chat->botStatus > 0 && user->isBot()) {
370 			chat->refreshBotStatus();
371 		}
372 	}
373 	chat->session().changes().peerUpdated(chat, UpdateFlag::Members);
374 }
375 
ApplyChatUpdate(not_null<ChatData * > chat,const MTPDupdateChatParticipantAdmin & update)376 void ApplyChatUpdate(
377 		not_null<ChatData*> chat,
378 		const MTPDupdateChatParticipantAdmin &update) {
379 	if (chat->applyUpdateVersion(update.vversion().v)
380 		!= ChatData::UpdateStatus::Good) {
381 		return;
382 	}
383 	const auto session = &chat->session();
384 	const auto user = chat->owner().userLoaded(update.vuser_id().v);
385 	if (!user) {
386 		chat->invalidateParticipants();
387 		return;
388 	}
389 	if (user->isSelf()) {
390 		chat->setAdminRights(mtpIsTrue(update.vis_admin())
391 			? chat->defaultAdminRights(user).flags
392 			: ChatAdminRights());
393 	}
394 	if (mtpIsTrue(update.vis_admin())) {
395 		if (chat->noParticipantInfo()) {
396 			session->api().requestFullPeer(chat);
397 		} else {
398 			chat->admins.emplace(user);
399 		}
400 	} else {
401 		chat->admins.erase(user);
402 	}
403 	session->changes().peerUpdated(chat, UpdateFlag::Admins);
404 }
405 
ApplyChatUpdate(not_null<ChatData * > chat,const MTPDupdateChatDefaultBannedRights & update)406 void ApplyChatUpdate(
407 		not_null<ChatData*> chat,
408 		const MTPDupdateChatDefaultBannedRights &update) {
409 	if (chat->applyUpdateVersion(update.vversion().v)
410 		!= ChatData::UpdateStatus::Good) {
411 		return;
412 	}
413 	chat->setDefaultRestrictions(Data::ChatBannedRightsFlags(
414 		update.vdefault_banned_rights()));
415 }
416 
ApplyChatUpdate(not_null<ChatData * > chat,const MTPDchatFull & update)417 void ApplyChatUpdate(not_null<ChatData*> chat, const MTPDchatFull &update) {
418 	ApplyChatUpdate(chat, update.vparticipants());
419 
420 	if (const auto call = update.vcall()) {
421 		chat->setGroupCall(*call);
422 	} else {
423 		chat->clearGroupCall();
424 	}
425 	if (const auto as = update.vgroupcall_default_join_as()) {
426 		chat->setGroupCallDefaultJoinAs(peerFromMTP(*as));
427 	} else {
428 		chat->setGroupCallDefaultJoinAs(0);
429 	}
430 
431 	chat->setMessagesTTL(update.vttl_period().value_or_empty());
432 	if (const auto info = update.vbot_info()) {
433 		chat->setBotCommands(*info);
434 	} else {
435 		chat->setBotCommands(MTP_vector<MTPBotInfo>());
436 	}
437 	using Flag = ChatDataFlag;
438 	const auto mask = Flag::CanSetUsername;
439 	chat->setFlags((chat->flags() & ~mask)
440 		| (update.is_can_set_username() ? Flag::CanSetUsername : Flag()));
441 	if (const auto photo = update.vchat_photo()) {
442 		chat->setUserpicPhoto(*photo);
443 	} else {
444 		chat->setUserpicPhoto(MTP_photoEmpty(MTP_long(0)));
445 	}
446 	if (const auto invite = update.vexported_invite()) {
447 		chat->session().api().inviteLinks().setMyPermanent(chat, *invite);
448 	} else {
449 		chat->session().api().inviteLinks().clearMyPermanent(chat);
450 	}
451 	if (const auto pinned = update.vpinned_msg_id()) {
452 		SetTopPinnedMessageId(chat, pinned->v);
453 	}
454 	chat->checkFolder(update.vfolder_id().value_or_empty());
455 	chat->setThemeEmoji(qs(update.vtheme_emoticon().value_or_empty()));
456 	chat->fullUpdated();
457 	chat->setAbout(qs(update.vabout()));
458 	chat->setPendingRequestsCount(
459 		update.vrequests_pending().value_or_empty(),
460 		update.vrecent_requesters().value_or_empty());
461 
462 	chat->session().api().applyNotifySettings(
463 		MTP_inputNotifyPeer(chat->input),
464 		update.vnotify_settings());
465 }
466 
ApplyChatUpdate(not_null<ChatData * > chat,const MTPChatParticipants & participants)467 void ApplyChatUpdate(
468 		not_null<ChatData*> chat,
469 		const MTPChatParticipants &participants) {
470 	const auto session = &chat->session();
471 	participants.match([&](const MTPDchatParticipantsForbidden &data) {
472 		if (const auto self = data.vself_participant()) {
473 			// self->
474 		}
475 		chat->count = -1;
476 		chat->invalidateParticipants();
477 	}, [&](const MTPDchatParticipants &data) {
478 		const auto status = chat->applyUpdateVersion(data.vversion().v);
479 		if (status == ChatData::UpdateStatus::TooOld) {
480 			return;
481 		}
482 		// Even if we skipped some updates, we got current participants
483 		// and we've requested peer from API to have current rights.
484 		chat->setVersion(data.vversion().v);
485 
486 		const auto &list = data.vparticipants().v;
487 		chat->count = list.size();
488 		chat->participants.clear();
489 		chat->invitedByMe.clear();
490 		chat->admins.clear();
491 		chat->setAdminRights(ChatAdminRights());
492 		const auto selfUserId = session->userId();
493 		for (const auto &participant : list) {
494 			const auto userId = participant.match([&](const auto &data) {
495 				return data.vuser_id().v;
496 			});
497 			const auto user = chat->owner().userLoaded(userId);
498 			if (!user) {
499 				chat->invalidateParticipants();
500 				break;
501 			}
502 
503 			chat->participants.emplace(user);
504 
505 			const auto inviterId = participant.match([&](
506 					const MTPDchatParticipantCreator &data) {
507 				return UserId(0);
508 			}, [&](const auto &data) {
509 				return UserId(data.vinviter_id());
510 			});
511 			if (inviterId == selfUserId) {
512 				chat->invitedByMe.insert(user);
513 			}
514 
515 			participant.match([&](const MTPDchatParticipantCreator &data) {
516 				chat->creator = userId;
517 			}, [&](const MTPDchatParticipantAdmin &data) {
518 				chat->admins.emplace(user);
519 				if (user->isSelf()) {
520 					chat->setAdminRights(
521 						chat->defaultAdminRights(user).flags);
522 				}
523 			}, [](const MTPDchatParticipant &) {
524 			});
525 		}
526 		if (chat->participants.empty()) {
527 			return;
528 		}
529 		if (const auto history = chat->owner().historyLoaded(chat)) {
530 			if (history->lastKeyboardFrom) {
531 				const auto i = ranges::find(
532 					chat->participants,
533 					history->lastKeyboardFrom,
534 					&UserData::id);
535 				if (i == end(chat->participants)) {
536 					history->clearLastKeyboard();
537 				}
538 			}
539 		}
540 		chat->refreshBotStatus();
541 		session->changes().peerUpdated(
542 			chat,
543 			UpdateFlag::Members | UpdateFlag::Admins);
544 	});
545 }
546 
547 } // namespace Data
548