data_chat.cpp 15 KB

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