data_histories.cpp 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224
  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_histories.h"
  8. #include "api/api_text_entities.h"
  9. #include "data/business/data_shortcut_messages.h"
  10. #include "data/components/scheduled_messages.h"
  11. #include "data/data_session.h"
  12. #include "data/data_channel.h"
  13. #include "data/data_chat.h"
  14. #include "data/data_folder.h"
  15. #include "data/data_forum.h"
  16. #include "data/data_forum_topic.h"
  17. #include "data/data_user.h"
  18. #include "base/unixtime.h"
  19. #include "base/random.h"
  20. #include "main/main_session.h"
  21. #include "window/notifications_manager.h"
  22. #include "history/history.h"
  23. #include "history/history_item.h"
  24. #include "history/history_item_helpers.h"
  25. #include "history/view/history_view_element.h"
  26. #include "core/application.h"
  27. #include "apiwrap.h"
  28. namespace Data {
  29. namespace {
  30. constexpr auto kReadRequestTimeout = 3 * crl::time(1000);
  31. constexpr auto kReportDeliveriesPerRequest = 50;
  32. } // namespace
  33. MTPInputReplyTo ReplyToForMTP(
  34. not_null<History*> history,
  35. FullReplyTo replyTo) {
  36. const auto owner = &history->owner();
  37. if (replyTo.storyId) {
  38. if (const auto peer = owner->peerLoaded(replyTo.storyId.peer)) {
  39. return MTP_inputReplyToStory(
  40. peer->input,
  41. MTP_int(replyTo.storyId.story));
  42. }
  43. } else if (replyTo.messageId || replyTo.topicRootId) {
  44. const auto to = LookupReplyTo(history, replyTo.messageId);
  45. const auto replyingToTopic = replyTo.topicRootId
  46. ? history->peer->forumTopicFor(replyTo.topicRootId)
  47. : nullptr;
  48. const auto replyingToTopicId = replyTo.topicRootId
  49. ? (replyingToTopic
  50. ? replyingToTopic->rootId()
  51. : Data::ForumTopic::kGeneralId)
  52. : (to ? to->topicRootId() : Data::ForumTopic::kGeneralId);
  53. const auto replyToTopicId = (to
  54. && (to->history() != history || to->id != replyingToTopicId))
  55. ? to->topicRootId()
  56. : replyingToTopicId;
  57. const auto external = replyTo.messageId
  58. && (replyTo.messageId.peer != history->peer->id
  59. || replyingToTopicId != replyToTopicId);
  60. const auto quoteEntities = Api::EntitiesToMTP(
  61. &history->session(),
  62. replyTo.quote.entities,
  63. Api::ConvertOption::SkipLocal);
  64. using Flag = MTPDinputReplyToMessage::Flag;
  65. return MTP_inputReplyToMessage(
  66. MTP_flags((replyTo.topicRootId ? Flag::f_top_msg_id : Flag())
  67. | (external ? Flag::f_reply_to_peer_id : Flag())
  68. | (replyTo.quote.text.isEmpty()
  69. ? Flag()
  70. : (Flag::f_quote_text | Flag::f_quote_offset))
  71. | (quoteEntities.v.isEmpty()
  72. ? Flag()
  73. : Flag::f_quote_entities)),
  74. MTP_int(replyTo.messageId ? replyTo.messageId.msg : 0),
  75. MTP_int(replyTo.topicRootId),
  76. (external
  77. ? owner->peer(replyTo.messageId.peer)->input
  78. : MTPInputPeer()),
  79. MTP_string(replyTo.quote.text),
  80. quoteEntities,
  81. MTP_int(replyTo.quoteOffset));
  82. }
  83. return MTPInputReplyTo();
  84. }
  85. MTPInputMedia WebPageForMTP(
  86. const Data::WebPageDraft &draft,
  87. bool required) {
  88. using Flag = MTPDinputMediaWebPage::Flag;
  89. return MTP_inputMediaWebPage(
  90. MTP_flags(((false && required) ? Flag() : Flag::f_optional)
  91. | (draft.forceLargeMedia ? Flag::f_force_large_media : Flag())
  92. | (draft.forceSmallMedia ? Flag::f_force_small_media : Flag())),
  93. MTP_string(draft.url));
  94. }
  95. Histories::Histories(not_null<Session*> owner)
  96. : _owner(owner)
  97. , _readRequestsTimer([=] { sendReadRequests(); }) {
  98. }
  99. Session &Histories::owner() const {
  100. return *_owner;
  101. }
  102. Main::Session &Histories::session() const {
  103. return _owner->session();
  104. }
  105. History *Histories::find(PeerId peerId) {
  106. const auto i = peerId ? _map.find(peerId) : end(_map);
  107. return (i != end(_map)) ? i->second.get() : nullptr;
  108. }
  109. not_null<History*> Histories::findOrCreate(PeerId peerId) {
  110. Expects(peerId != 0);
  111. if (const auto result = find(peerId)) {
  112. return result;
  113. }
  114. const auto &[i, ok] = _map.emplace(
  115. peerId,
  116. std::make_unique<History>(&owner(), peerId));
  117. return i->second.get();
  118. }
  119. void Histories::unloadAll() {
  120. for (const auto &[peerId, history] : _map) {
  121. history->clear(History::ClearType::Unload);
  122. }
  123. }
  124. void Histories::clearAll() {
  125. _map.clear();
  126. }
  127. void Histories::readInbox(not_null<History*> history) {
  128. DEBUG_LOG(("Reading: readInbox called."));
  129. if (history->lastServerMessageKnown()) {
  130. const auto last = history->lastServerMessage();
  131. DEBUG_LOG(("Reading: last known, reading till %1."
  132. ).arg(last ? last->id.bare : 0));
  133. readInboxTill(history, last ? last->id : 0);
  134. return;
  135. } else if (history->loadedAtBottom()) {
  136. if (const auto lastId = history->maxMsgId()) {
  137. DEBUG_LOG(("Reading: loaded at bottom, maxMsgId %1."
  138. ).arg(lastId.bare));
  139. readInboxTill(history, lastId);
  140. return;
  141. } else if (history->loadedAtTop()) {
  142. DEBUG_LOG(("Reading: loaded at bottom, loaded at top."));
  143. readInboxTill(history, 0);
  144. return;
  145. }
  146. DEBUG_LOG(("Reading: loaded at bottom, but requesting entry."));
  147. }
  148. requestDialogEntry(history, [=] {
  149. Expects(history->lastServerMessageKnown());
  150. const auto last = history->lastServerMessage();
  151. DEBUG_LOG(("Reading: got entry, reading till %1."
  152. ).arg(last ? last->id.bare : 0));
  153. readInboxTill(history, last ? last->id : 0);
  154. });
  155. }
  156. void Histories::readInboxTill(not_null<HistoryItem*> item) {
  157. const auto history = item->history();
  158. if (!item->isRegular()) {
  159. readClientSideMessage(item);
  160. auto view = item->mainView();
  161. if (!view) {
  162. return;
  163. }
  164. auto block = view->block();
  165. auto blockIndex = block->indexInHistory();
  166. auto itemIndex = view->indexInBlock();
  167. while (blockIndex > 0 || itemIndex > 0) {
  168. if (itemIndex > 0) {
  169. view = block->messages[--itemIndex].get();
  170. } else {
  171. while (blockIndex > 0) {
  172. block = history->blocks[--blockIndex].get();
  173. itemIndex = block->messages.size();
  174. if (itemIndex > 0) {
  175. view = block->messages[--itemIndex].get();
  176. break;
  177. }
  178. }
  179. }
  180. item = view->data();
  181. if (item->isRegular()) {
  182. break;
  183. }
  184. }
  185. if (!item->isRegular()) {
  186. LOG(("App Error: "
  187. "Can't read history till unknown local message."));
  188. return;
  189. }
  190. }
  191. readInboxTill(history, item->id);
  192. }
  193. void Histories::readInboxTill(not_null<History*> history, MsgId tillId) {
  194. readInboxTill(history, tillId, false);
  195. }
  196. void Histories::readInboxTill(
  197. not_null<History*> history,
  198. MsgId tillId,
  199. bool force) {
  200. Expects(IsServerMsgId(tillId) || (!tillId && !force));
  201. DEBUG_LOG(("Reading: readInboxTill %1, force %2."
  202. ).arg(tillId.bare
  203. ).arg(Logs::b(force)));
  204. const auto syncGuard = gsl::finally([&] {
  205. DEBUG_LOG(("Reading: in guard, unread %1."
  206. ).arg(history->unreadCount()));
  207. if (history->unreadCount() > 0) {
  208. if (const auto last = history->lastServerMessage()) {
  209. DEBUG_LOG(("Reading: checking last %1 and %2."
  210. ).arg(last->id.bare
  211. ).arg(tillId.bare));
  212. if (last->id == tillId) {
  213. DEBUG_LOG(("Reading: locally marked as read."));
  214. history->setUnreadCount(0);
  215. history->updateChatListEntry();
  216. }
  217. }
  218. }
  219. });
  220. Core::App().notifications().clearIncomingFromHistory(history);
  221. const auto needsRequest = history->readInboxTillNeedsRequest(tillId);
  222. if (!needsRequest && !force) {
  223. DEBUG_LOG(("Reading: readInboxTill finish 1."));
  224. return;
  225. } else if (!history->trackUnreadMessages()) {
  226. DEBUG_LOG(("Reading: readInboxTill finish 2."));
  227. return;
  228. }
  229. const auto maybeState = lookup(history);
  230. if (maybeState && maybeState->sentReadTill >= tillId) {
  231. DEBUG_LOG(("Reading: readInboxTill finish 3 with %1."
  232. ).arg(maybeState->sentReadTill.bare));
  233. return;
  234. } else if (maybeState && maybeState->willReadTill >= tillId) {
  235. DEBUG_LOG(("Reading: readInboxTill finish 4 with %1 and force %2."
  236. ).arg(maybeState->sentReadTill.bare
  237. ).arg(Logs::b(force)));
  238. if (force) {
  239. sendPendingReadInbox(history);
  240. }
  241. return;
  242. } else if (!needsRequest
  243. && (!maybeState || !maybeState->willReadTill)) {
  244. return;
  245. }
  246. const auto stillUnread = history->countStillUnreadLocal(tillId);
  247. if (!force
  248. && stillUnread
  249. && history->unreadCountKnown()
  250. && *stillUnread == history->unreadCount()) {
  251. DEBUG_LOG(("Reading: count didn't change so just update till %1"
  252. ).arg(tillId.bare));
  253. history->setInboxReadTill(tillId);
  254. return;
  255. }
  256. auto &state = maybeState ? *maybeState : _states[history];
  257. state.willReadTill = tillId;
  258. if (force || !stillUnread || !*stillUnread) {
  259. DEBUG_LOG(("Reading: will read till %1 with still unread %2"
  260. ).arg(tillId.bare
  261. ).arg(stillUnread.value_or(-666)));
  262. state.willReadWhen = 0;
  263. sendReadRequests();
  264. if (!stillUnread) {
  265. return;
  266. }
  267. } else if (!state.willReadWhen) {
  268. DEBUG_LOG(("Reading: will read till %1 with postponed"
  269. ).arg(tillId.bare));
  270. state.willReadWhen = crl::now() + kReadRequestTimeout;
  271. if (!_readRequestsTimer.isActive()) {
  272. _readRequestsTimer.callOnce(kReadRequestTimeout);
  273. }
  274. } else {
  275. DEBUG_LOG(("Reading: will read till %1 postponed already"
  276. ).arg(tillId.bare));
  277. }
  278. DEBUG_LOG(("Reading: marking now with till %1 and still %2"
  279. ).arg(tillId.bare
  280. ).arg(*stillUnread));
  281. history->setInboxReadTill(tillId);
  282. history->setUnreadCount(*stillUnread);
  283. history->updateChatListEntry();
  284. }
  285. void Histories::readInboxOnNewMessage(not_null<HistoryItem*> item) {
  286. if (!item->isRegular()) {
  287. readClientSideMessage(item);
  288. } else {
  289. readInboxTill(item->history(), item->id, true);
  290. }
  291. }
  292. void Histories::readClientSideMessage(not_null<HistoryItem*> item) {
  293. if (item->out() || !item->unread(item->history())) {
  294. return;
  295. }
  296. const auto history = item->history();
  297. item->markClientSideAsRead();
  298. if (const auto unread = history->unreadCount()) {
  299. history->setUnreadCount(unread - 1);
  300. }
  301. }
  302. void Histories::requestDialogEntry(not_null<Data::Folder*> folder) {
  303. if (_dialogFolderRequests.contains(folder)) {
  304. return;
  305. }
  306. _dialogFolderRequests.emplace(folder);
  307. auto peers = QVector<MTPInputDialogPeer>(
  308. 1,
  309. MTP_inputDialogPeerFolder(MTP_int(folder->id())));
  310. session().api().request(MTPmessages_GetPeerDialogs(
  311. MTP_vector(std::move(peers))
  312. )).done([=](const MTPmessages_PeerDialogs &result) {
  313. applyPeerDialogs(result);
  314. _dialogFolderRequests.remove(folder);
  315. }).fail([=] {
  316. _dialogFolderRequests.remove(folder);
  317. }).send();
  318. }
  319. void Histories::requestDialogEntry(
  320. not_null<History*> history,
  321. Fn<void()> callback) {
  322. const auto i = _dialogRequests.find(history);
  323. if (i != end(_dialogRequests)) {
  324. if (callback) {
  325. i->second.push_back(std::move(callback));
  326. }
  327. return;
  328. }
  329. const auto &[j, ok] = _dialogRequestsPending.try_emplace(history);
  330. if (callback) {
  331. j->second.push_back(std::move(callback));
  332. }
  333. if (!ok) {
  334. return;
  335. }
  336. postponeRequestDialogEntries();
  337. }
  338. void Histories::postponeRequestDialogEntries() {
  339. if (_dialogRequestsPending.size() > 1) {
  340. return;
  341. }
  342. Core::App().postponeCall(crl::guard(&session(), [=] {
  343. sendDialogRequests();
  344. }));
  345. }
  346. void Histories::sendDialogRequests() {
  347. if (_dialogRequestsPending.empty()) {
  348. return;
  349. }
  350. const auto histories = ranges::views::all(
  351. _dialogRequestsPending
  352. ) | ranges::views::transform([](const auto &pair) {
  353. return pair.first;
  354. }) | ranges::views::filter([&](not_null<History*> history) {
  355. const auto state = lookup(history);
  356. if (!state) {
  357. return true;
  358. } else if (!postponeEntryRequest(*state)) {
  359. return true;
  360. }
  361. state->postponedRequestEntry = true;
  362. return false;
  363. }) | ranges::to_vector;
  364. auto peers = QVector<MTPInputDialogPeer>();
  365. const auto dialogPeer = [](not_null<History*> history) {
  366. return MTP_inputDialogPeer(history->peer->input);
  367. };
  368. ranges::transform(
  369. histories,
  370. ranges::back_inserter(peers),
  371. dialogPeer);
  372. for (auto &[history, callbacks] : base::take(_dialogRequestsPending)) {
  373. _dialogRequests.emplace(history, std::move(callbacks));
  374. }
  375. const auto finalize = [=] {
  376. for (const auto &history : histories) {
  377. const auto state = lookup(history);
  378. if (!state || !state->postponedRequestEntry) {
  379. dialogEntryApplied(history);
  380. history->updateChatListExistence();
  381. }
  382. }
  383. };
  384. session().api().request(MTPmessages_GetPeerDialogs(
  385. MTP_vector(std::move(peers))
  386. )).done([=](const MTPmessages_PeerDialogs &result) {
  387. applyPeerDialogs(result);
  388. finalize();
  389. }).fail([=] {
  390. finalize();
  391. }).send();
  392. }
  393. void Histories::dialogEntryApplied(not_null<History*> history) {
  394. const auto state = lookup(history);
  395. if (state && state->postponedRequestEntry) {
  396. return;
  397. }
  398. history->dialogEntryApplied();
  399. if (const auto callbacks = _dialogRequestsPending.take(history)) {
  400. for (const auto &callback : *callbacks) {
  401. callback();
  402. }
  403. }
  404. if (const auto callbacks = _dialogRequests.take(history)) {
  405. for (const auto &callback : *callbacks) {
  406. callback();
  407. }
  408. }
  409. if (state && state->sentReadTill && state->sentReadDone) {
  410. history->setInboxReadTill(base::take(state->sentReadTill));
  411. checkEmptyState(history);
  412. }
  413. }
  414. void Histories::applyPeerDialogs(const MTPmessages_PeerDialogs &dialogs) {
  415. Expects(dialogs.type() == mtpc_messages_peerDialogs);
  416. const auto &data = dialogs.c_messages_peerDialogs();
  417. _owner->processUsers(data.vusers());
  418. _owner->processChats(data.vchats());
  419. _owner->processMessages(data.vmessages(), NewMessageType::Last);
  420. for (const auto &dialog : data.vdialogs().v) {
  421. dialog.match([&](const MTPDdialog &data) {
  422. if (const auto peerId = peerFromMTP(data.vpeer())) {
  423. _owner->history(peerId)->applyDialog(nullptr, data);
  424. }
  425. }, [&](const MTPDdialogFolder &data) {
  426. const auto folder = _owner->processFolder(data.vfolder());
  427. folder->applyDialog(data);
  428. });
  429. }
  430. _owner->sendHistoryChangeNotifications();
  431. }
  432. void Histories::changeDialogUnreadMark(
  433. not_null<History*> history,
  434. bool unread) {
  435. history->setUnreadMark(unread);
  436. using Flag = MTPmessages_MarkDialogUnread::Flag;
  437. session().api().request(MTPmessages_MarkDialogUnread(
  438. MTP_flags(unread ? Flag::f_unread : Flag(0)),
  439. MTP_inputDialogPeer(history->peer->input)
  440. )).send();
  441. }
  442. void Histories::requestFakeChatListMessage(
  443. not_null<History*> history) {
  444. if (_fakeChatListRequests.contains(history)) {
  445. return;
  446. }
  447. _fakeChatListRequests.emplace(history);
  448. sendRequest(history, RequestType::History, [=](Fn<void()> finish) {
  449. return session().api().request(MTPmessages_GetHistory(
  450. history->peer->input,
  451. MTP_int(0), // offset_id
  452. MTP_int(0), // offset_date
  453. MTP_int(0), // add_offset
  454. MTP_int(2), // limit
  455. MTP_int(0), // max_id
  456. MTP_int(0), // min_id
  457. MTP_long(0) // hash
  458. )).done([=](const MTPmessages_Messages &result) {
  459. _fakeChatListRequests.erase(history);
  460. history->setFakeChatListMessageFrom(result);
  461. finish();
  462. }).fail([=] {
  463. _fakeChatListRequests.erase(history);
  464. history->setFakeChatListMessageFrom(MTP_messages_messages(
  465. MTP_vector<MTPMessage>(0),
  466. MTP_vector<MTPChat>(0),
  467. MTP_vector<MTPUser>(0)));
  468. finish();
  469. }).send();
  470. });
  471. }
  472. void Histories::requestGroupAround(not_null<HistoryItem*> item) {
  473. const auto history = item->history();
  474. const auto id = item->id;
  475. const auto key = GroupRequestKey{ history, item->topicRootId() };
  476. const auto i = _chatListGroupRequests.find(key);
  477. if (i != end(_chatListGroupRequests)) {
  478. if (i->second.aroundId == id) {
  479. return;
  480. } else {
  481. cancelRequest(i->second.requestId);
  482. _chatListGroupRequests.erase(i);
  483. }
  484. }
  485. constexpr auto kMaxAlbumCount = 10;
  486. const auto requestId = sendRequest(history, RequestType::History, [=](
  487. Fn<void()> finish) {
  488. return session().api().request(MTPmessages_GetHistory(
  489. history->peer->input,
  490. MTP_int(id),
  491. MTP_int(0), // offset_date
  492. MTP_int(-kMaxAlbumCount),
  493. MTP_int(2 * kMaxAlbumCount - 1),
  494. MTP_int(0), // max_id
  495. MTP_int(0), // min_id
  496. MTP_long(0) // hash
  497. )).done([=](const MTPmessages_Messages &result) {
  498. _owner->processExistingMessages(
  499. history->peer->asChannel(),
  500. result);
  501. _chatListGroupRequests.remove(key);
  502. history->migrateToOrMe()->applyChatListGroup(
  503. history->peer->id,
  504. result);
  505. finish();
  506. }).fail([=] {
  507. _chatListGroupRequests.remove(key);
  508. finish();
  509. }).send();
  510. });
  511. _chatListGroupRequests.emplace(
  512. key,
  513. ChatListGroupRequest{ .aroundId = id, .requestId = requestId });
  514. }
  515. void Histories::sendPendingReadInbox(not_null<History*> history) {
  516. if (const auto state = lookup(history)) {
  517. DEBUG_LOG(("Reading: send pending now with till %1 and when %2"
  518. ).arg(state->willReadTill.bare
  519. ).arg(state->willReadWhen));
  520. if (state->willReadTill && state->willReadWhen) {
  521. state->willReadWhen = 0;
  522. sendReadRequests();
  523. }
  524. }
  525. }
  526. void Histories::reportDelivery(not_null<HistoryItem*> item) {
  527. auto &set = _pendingDeliveryReport[item->history()->peer];
  528. if (!set.emplace(item->id).second) {
  529. return;
  530. }
  531. crl::on_main(&session(), [=] {
  532. reportPendingDeliveries();
  533. });
  534. }
  535. void Histories::reportPendingDeliveries() {
  536. auto &pending = _pendingDeliveryReport;
  537. for (auto i = begin(pending); i != end(pending);) {
  538. auto &[peer, ids] = *i;
  539. auto list = QVector<MTPint>();
  540. if (_deliveryReportSent.contains(peer)) {
  541. ++i;
  542. continue;
  543. } else if (ids.size() > kReportDeliveriesPerRequest) {
  544. const auto count = kReportDeliveriesPerRequest;
  545. list.reserve(count);
  546. for (auto j = begin(ids), till = j + count; j != till; ++j) {
  547. list.push_back(MTP_int(*j));
  548. }
  549. ids.erase(begin(ids), begin(ids) + count);
  550. } else if (!ids.empty()) {
  551. list.reserve(ids.size());
  552. for (const auto &id : ids) {
  553. list.push_back(MTP_int(id));
  554. }
  555. ids.clear();
  556. }
  557. if (ids.empty()) {
  558. i = pending.erase(i);
  559. } else {
  560. ++i;
  561. }
  562. _deliveryReportSent.emplace(peer);
  563. const auto finish = [=] {
  564. _deliveryReportSent.remove(peer);
  565. if (_pendingDeliveryReport.contains(peer)) {
  566. reportPendingDeliveries();
  567. }
  568. };
  569. session().api().request(MTPmessages_ReportMessagesDelivery(
  570. MTP_flags(0),
  571. peer->input,
  572. MTP_vector(std::move(list))
  573. )).done(finish).fail(finish).send();
  574. }
  575. }
  576. void Histories::sendReadRequests() {
  577. DEBUG_LOG(("Reading: send requests with count %1.").arg(_states.size()));
  578. if (_states.empty()) {
  579. return;
  580. }
  581. const auto now = crl::now();
  582. auto next = std::optional<crl::time>();
  583. for (auto &[history, state] : _states) {
  584. if (!state.willReadTill) {
  585. DEBUG_LOG(("Reading: skipping zero till."));
  586. continue;
  587. } else if (state.willReadWhen <= now) {
  588. DEBUG_LOG(("Reading: sending with till %1."
  589. ).arg(state.willReadTill.bare));
  590. sendReadRequest(history, state);
  591. } else if (!next || *next > state.willReadWhen) {
  592. DEBUG_LOG(("Reading: scheduling for later send."));
  593. next = state.willReadWhen;
  594. }
  595. }
  596. if (next.has_value()) {
  597. _readRequestsTimer.callOnce(*next - now);
  598. } else {
  599. _readRequestsTimer.cancel();
  600. }
  601. }
  602. void Histories::sendReadRequest(not_null<History*> history, State &state) {
  603. Expects(state.willReadTill > state.sentReadTill);
  604. const auto tillId = state.sentReadTill = base::take(state.willReadTill);
  605. state.willReadWhen = 0;
  606. state.sentReadDone = false;
  607. DEBUG_LOG(("Reading: sending request now with till %1."
  608. ).arg(tillId.bare));
  609. sendRequest(history, RequestType::ReadInbox, [=](Fn<void()> finish) {
  610. DEBUG_LOG(("Reading: sending request invoked with till %1."
  611. ).arg(tillId.bare));
  612. const auto finished = [=] {
  613. const auto state = lookup(history);
  614. Assert(state != nullptr);
  615. if (state->sentReadTill == tillId) {
  616. state->sentReadDone = true;
  617. if (history->unreadCountRefreshNeeded(tillId)) {
  618. requestDialogEntry(history);
  619. } else {
  620. state->sentReadTill = 0;
  621. }
  622. } else {
  623. Assert(!state->sentReadTill || state->sentReadTill > tillId);
  624. }
  625. sendReadRequests();
  626. finish();
  627. };
  628. if (const auto channel = history->peer->asChannel()) {
  629. return session().api().request(MTPchannels_ReadHistory(
  630. channel->inputChannel,
  631. MTP_int(tillId)
  632. )).done(finished).fail(finished).send();
  633. } else {
  634. return session().api().request(MTPmessages_ReadHistory(
  635. history->peer->input,
  636. MTP_int(tillId)
  637. )).done([=](const MTPmessages_AffectedMessages &result) {
  638. session().api().applyAffectedMessages(history->peer, result);
  639. finished();
  640. }).fail([=] {
  641. finished();
  642. }).send();
  643. }
  644. });
  645. }
  646. void Histories::checkEmptyState(not_null<History*> history) {
  647. const auto empty = [](const State &state) {
  648. return state.postponed.empty()
  649. && !state.postponedRequestEntry
  650. && state.sent.empty()
  651. && (state.willReadTill == 0)
  652. && (state.sentReadTill == 0);
  653. };
  654. const auto i = _states.find(history);
  655. if (i != end(_states) && empty(i->second)) {
  656. _states.erase(i);
  657. }
  658. }
  659. bool Histories::postponeHistoryRequest(const State &state) const {
  660. const auto proj = [](const auto &pair) {
  661. return pair.second.type;
  662. };
  663. const auto i = ranges::find(state.sent, RequestType::Delete, proj);
  664. return (i != end(state.sent));
  665. }
  666. bool Histories::postponeEntryRequest(const State &state) const {
  667. return ranges::any_of(state.sent, [](const auto &pair) {
  668. return pair.second.type != RequestType::History;
  669. });
  670. }
  671. void Histories::deleteMessages(
  672. not_null<History*> history,
  673. const QVector<MTPint> &ids,
  674. bool revoke) {
  675. sendRequest(history, RequestType::Delete, [=](Fn<void()> finish) {
  676. const auto done = [=](const MTPmessages_AffectedMessages &result) {
  677. session().api().applyAffectedMessages(history->peer, result);
  678. finish();
  679. history->requestChatListMessage();
  680. };
  681. if (const auto channel = history->peer->asChannel()) {
  682. return session().api().request(MTPchannels_DeleteMessages(
  683. channel->inputChannel,
  684. MTP_vector<MTPint>(ids)
  685. )).done(done).fail(finish).send();
  686. } else {
  687. using Flag = MTPmessages_DeleteMessages::Flag;
  688. return session().api().request(MTPmessages_DeleteMessages(
  689. MTP_flags(revoke ? Flag::f_revoke : Flag(0)),
  690. MTP_vector<MTPint>(ids)
  691. )).done(done).fail(finish).send();
  692. }
  693. });
  694. }
  695. void Histories::deleteAllMessages(
  696. not_null<History*> history,
  697. MsgId deleteTillId,
  698. bool justClear,
  699. bool revoke) {
  700. sendRequest(history, RequestType::Delete, [=](Fn<void()> finish) {
  701. const auto peer = history->peer;
  702. const auto chat = peer->asChat();
  703. const auto channel = peer->asChannel();
  704. if (!justClear && revoke && channel && channel->canDelete()) {
  705. return session().api().request(MTPchannels_DeleteChannel(
  706. channel->inputChannel
  707. )).done([=](const MTPUpdates &result) {
  708. session().api().applyUpdates(result);
  709. //}).fail([=](const MTP::Error &error) {
  710. // if (error.type() == u"CHANNEL_TOO_LARGE"_q) {
  711. // Ui::show(Box<Ui::InformBox>(tr::lng_cant_delete_channel(tr::now)));
  712. // }
  713. }).send();
  714. } else if (channel) {
  715. using Flag = MTPchannels_DeleteHistory::Flag;
  716. return session().api().request(MTPchannels_DeleteHistory(
  717. MTP_flags(revoke ? Flag::f_for_everyone : Flag(0)),
  718. channel->inputChannel,
  719. MTP_int(deleteTillId)
  720. )).done(finish).fail(finish).send();
  721. } else if (revoke && chat && chat->amCreator()) {
  722. return session().api().request(MTPmessages_DeleteChat(
  723. chat->inputChat
  724. )).done(finish).fail([=](const MTP::Error &error) {
  725. if (error.type() == "PEER_ID_INVALID") {
  726. // Try to join and delete,
  727. // while delete fails for non-joined.
  728. session().api().request(MTPmessages_AddChatUser(
  729. chat->inputChat,
  730. MTP_inputUserSelf(),
  731. MTP_int(0)
  732. )).done([=](const MTPmessages_InvitedUsers &result) {
  733. const auto &data = result.data();
  734. session().api().applyUpdates(data.vupdates());
  735. deleteAllMessages(
  736. history,
  737. deleteTillId,
  738. justClear,
  739. revoke);
  740. }).send();
  741. }
  742. finish();
  743. }).send();
  744. } else {
  745. using Flag = MTPmessages_DeleteHistory::Flag;
  746. const auto flags = Flag(0)
  747. | (justClear ? Flag::f_just_clear : Flag(0))
  748. | (revoke ? Flag::f_revoke : Flag(0));
  749. return session().api().request(MTPmessages_DeleteHistory(
  750. MTP_flags(flags),
  751. peer->input,
  752. MTP_int(0),
  753. MTPint(), // min_date
  754. MTPint() // max_date
  755. )).done([=](const MTPmessages_AffectedHistory &result) {
  756. const auto offset = session().api().applyAffectedHistory(
  757. peer,
  758. result);
  759. if (offset > 0) {
  760. deleteAllMessages(
  761. history,
  762. deleteTillId,
  763. justClear,
  764. revoke);
  765. }
  766. finish();
  767. }).fail(finish).send();
  768. }
  769. });
  770. }
  771. void Histories::deleteMessagesByDates(
  772. not_null<History*> history,
  773. QDate firstDayToDelete,
  774. QDate lastDayToDelete,
  775. bool revoke) {
  776. const auto firstSecondToDelete = base::unixtime::serialize(
  777. { firstDayToDelete, QTime(0, 0) }
  778. );
  779. const auto lastSecondToDelete = base::unixtime::serialize(
  780. { lastDayToDelete, QTime(23, 59, 59) }
  781. );
  782. deleteMessagesByDates(
  783. history,
  784. firstSecondToDelete - 1,
  785. lastSecondToDelete + 1,
  786. revoke);
  787. }
  788. void Histories::deleteMessagesByDates(
  789. not_null<History*> history,
  790. TimeId minDate,
  791. TimeId maxDate,
  792. bool revoke) {
  793. sendRequest(history, RequestType::Delete, [=](Fn<void()> finish) {
  794. const auto peer = history->peer;
  795. using Flag = MTPmessages_DeleteHistory::Flag;
  796. const auto flags = Flag::f_just_clear
  797. | Flag::f_min_date
  798. | Flag::f_max_date
  799. | (revoke ? Flag::f_revoke : Flag(0));
  800. return session().api().request(MTPmessages_DeleteHistory(
  801. MTP_flags(flags),
  802. peer->input,
  803. MTP_int(0),
  804. MTP_int(minDate),
  805. MTP_int(maxDate)
  806. )).done([=](const MTPmessages_AffectedHistory &result) {
  807. const auto offset = session().api().applyAffectedHistory(
  808. peer,
  809. result);
  810. if (offset > 0) {
  811. deleteMessagesByDates(history, minDate, maxDate, revoke);
  812. }
  813. finish();
  814. }).fail(finish).send();
  815. });
  816. history->destroyMessagesByDates(minDate, maxDate);
  817. }
  818. void Histories::deleteMessages(const MessageIdsList &ids, bool revoke) {
  819. auto remove = std::vector<not_null<HistoryItem*>>();
  820. remove.reserve(ids.size());
  821. base::flat_map<not_null<History*>, QVector<MTPint>> idsByPeer;
  822. base::flat_map<not_null<PeerData*>, QVector<MTPint>> scheduledIdsByPeer;
  823. base::flat_map<BusinessShortcutId, QVector<MTPint>> quickIdsByShortcut;
  824. for (const auto &itemId : ids) {
  825. if (const auto item = _owner->message(itemId)) {
  826. const auto history = item->history();
  827. if (item->isScheduled()) {
  828. const auto wasOnServer = !item->isSending()
  829. && !item->hasFailed();
  830. auto &scheduled = _owner->session().scheduledMessages();
  831. if (wasOnServer) {
  832. scheduledIdsByPeer[history->peer].push_back(
  833. MTP_int(scheduled.lookupId(item)));
  834. } else {
  835. scheduled.removeSending(item);
  836. }
  837. continue;
  838. } else if (item->isBusinessShortcut()) {
  839. const auto wasOnServer = !item->isSending()
  840. && !item->hasFailed();
  841. if (wasOnServer) {
  842. quickIdsByShortcut[item->shortcutId()].push_back(MTP_int(
  843. _owner->shortcutMessages().lookupId(item)));
  844. } else {
  845. _owner->shortcutMessages().removeSending(item);
  846. }
  847. continue;
  848. }
  849. remove.push_back(item);
  850. if (item->isRegular()) {
  851. idsByPeer[history].push_back(MTP_int(itemId.msg));
  852. }
  853. }
  854. }
  855. for (const auto &[history, ids] : idsByPeer) {
  856. history->owner().histories().deleteMessages(history, ids, revoke);
  857. }
  858. for (const auto &[peer, ids] : scheduledIdsByPeer) {
  859. peer->session().api().request(MTPmessages_DeleteScheduledMessages(
  860. peer->input,
  861. MTP_vector<MTPint>(ids)
  862. )).done([peer = peer](const MTPUpdates &result) {
  863. peer->session().api().applyUpdates(result);
  864. }).send();
  865. }
  866. for (const auto &[shortcutId, ids] : quickIdsByShortcut) {
  867. const auto api = &_owner->session().api();
  868. api->request(MTPmessages_DeleteQuickReplyMessages(
  869. MTP_int(shortcutId),
  870. MTP_vector<MTPint>(ids)
  871. )).done([=](const MTPUpdates &result) {
  872. api->applyUpdates(result);
  873. }).send();
  874. }
  875. for (const auto item : remove) {
  876. const auto history = item->history();
  877. const auto wasLast = (history->lastMessage() == item);
  878. const auto wasInChats = (history->chatListMessage() == item);
  879. item->destroy();
  880. if (wasLast || wasInChats) {
  881. history->requestChatListMessage();
  882. }
  883. }
  884. }
  885. int Histories::sendRequest(
  886. not_null<History*> history,
  887. RequestType type,
  888. Fn<mtpRequestId(Fn<void()> finish)> generator) {
  889. Expects(type != RequestType::None);
  890. auto &state = _states[history];
  891. const auto id = ++_requestAutoincrement;
  892. _historyByRequest.emplace(id, history);
  893. if (type == RequestType::History && postponeHistoryRequest(state)) {
  894. state.postponed.emplace(
  895. id,
  896. PostponedHistoryRequest{ std::move(generator) });
  897. return id;
  898. }
  899. const auto requestId = generator([=] { checkPostponed(history, id); });
  900. state.sent.emplace(id, SentRequest{
  901. std::move(generator),
  902. requestId,
  903. type
  904. });
  905. if (!state.postponedRequestEntry
  906. && postponeEntryRequest(state)
  907. && _dialogRequests.contains(history)) {
  908. state.postponedRequestEntry = true;
  909. }
  910. if (postponeHistoryRequest(state)) {
  911. const auto resendHistoryRequest = [&](auto &pair) {
  912. auto &[id, sent] = pair;
  913. if (sent.type != RequestType::History) {
  914. return false;
  915. }
  916. state.postponed.emplace(
  917. id,
  918. PostponedHistoryRequest{ std::move(sent.generator) });
  919. session().api().request(sent.id).cancel();
  920. return true;
  921. };
  922. state.sent.erase(
  923. ranges::remove_if(state.sent, resendHistoryRequest),
  924. end(state.sent));
  925. }
  926. return id;
  927. }
  928. void Histories::sendCreateTopicRequest(
  929. not_null<History*> history,
  930. MsgId rootId) {
  931. Expects(history->peer->isChannel());
  932. const auto forum = history->asForum();
  933. Assert(forum != nullptr);
  934. const auto topic = forum->topicFor(rootId);
  935. Assert(topic != nullptr);
  936. const auto randomId = base::RandomValue<uint64>();
  937. session().data().registerMessageRandomId(
  938. randomId,
  939. { history->peer->id, rootId });
  940. const auto api = &session().api();
  941. using Flag = MTPchannels_CreateForumTopic::Flag;
  942. api->request(MTPchannels_CreateForumTopic(
  943. MTP_flags(Flag::f_icon_color
  944. | (topic->iconId() ? Flag::f_icon_emoji_id : Flag(0))),
  945. history->peer->asChannel()->inputChannel,
  946. MTP_string(topic->title()),
  947. MTP_int(topic->colorId()),
  948. MTP_long(topic->iconId()),
  949. MTP_long(randomId),
  950. MTPInputPeer() // send_as
  951. )).done([=](const MTPUpdates &result) {
  952. api->applyUpdates(result, randomId);
  953. }).fail([=](const MTP::Error &error) {
  954. api->sendMessageFail(error, history->peer, randomId);
  955. }).send();
  956. }
  957. bool Histories::isCreatingTopic(
  958. not_null<History*> history,
  959. MsgId rootId) const {
  960. const auto forum = history->asForum();
  961. return forum && forum->creating(rootId);
  962. }
  963. int Histories::sendPreparedMessage(
  964. not_null<History*> history,
  965. FullReplyTo replyTo,
  966. uint64 randomId,
  967. Fn<PreparedMessage(not_null<History*>, FullReplyTo)> message,
  968. Fn<void(const MTPUpdates&, const MTP::Response&)> done,
  969. Fn<void(const MTP::Error&, const MTP::Response&)> fail) {
  970. if (isCreatingTopic(history, replyTo.topicRootId)) {
  971. const auto id = ++_requestAutoincrement;
  972. const auto creatingId = FullMsgId(
  973. history->peer->id,
  974. replyTo.topicRootId);
  975. auto i = _creatingTopics.find(creatingId);
  976. if (i == end(_creatingTopics)) {
  977. sendCreateTopicRequest(history, replyTo.topicRootId);
  978. i = _creatingTopics.emplace(creatingId).first;
  979. }
  980. i->second.push_back({
  981. .randomId = randomId,
  982. .replyTo = replyTo.messageId,
  983. .message = std::move(message),
  984. .done = std::move(done),
  985. .fail = std::move(fail),
  986. .requestId = id,
  987. });
  988. _creatingTopicRequests.emplace(id);
  989. return id;
  990. }
  991. const auto realReplyTo = FullReplyTo{
  992. .messageId = convertTopicReplyToId(history, replyTo.messageId),
  993. .quote = replyTo.quote,
  994. .storyId = replyTo.storyId,
  995. .topicRootId = convertTopicReplyToId(history, replyTo.topicRootId),
  996. .quoteOffset = replyTo.quoteOffset,
  997. };
  998. return v::match(message(history, realReplyTo), [&](const auto &request) {
  999. const auto type = RequestType::Send;
  1000. return sendRequest(history, type, [=](Fn<void()> finish) {
  1001. const auto session = &_owner->session();
  1002. const auto api = &session->api();
  1003. history->sendRequestId = api->request(
  1004. base::duplicate(request)
  1005. ).done([=](
  1006. const MTPUpdates &result,
  1007. const MTP::Response &response) {
  1008. api->applyUpdates(result, randomId);
  1009. done(result, response);
  1010. finish();
  1011. }).fail([=](
  1012. const MTP::Error &error,
  1013. const MTP::Response &response) {
  1014. fail(error, response);
  1015. finish();
  1016. }).afterRequest(
  1017. history->sendRequestId
  1018. ).send();
  1019. return history->sendRequestId;
  1020. });
  1021. });
  1022. }
  1023. void Histories::checkTopicCreated(FullMsgId rootId, MsgId realRoot) {
  1024. const auto i = _creatingTopics.find(rootId);
  1025. if (i != end(_creatingTopics)) {
  1026. auto scheduled = base::take(i->second);
  1027. _creatingTopics.erase(i);
  1028. _createdTopicIds.emplace(rootId, realRoot);
  1029. const auto history = _owner->history(rootId.peer);
  1030. if (const auto forum = history->asForum()) {
  1031. forum->created(rootId.msg, realRoot);
  1032. }
  1033. for (auto &entry : scheduled) {
  1034. _creatingTopicRequests.erase(entry.requestId);
  1035. sendPreparedMessage(
  1036. history,
  1037. FullReplyTo{
  1038. .messageId = entry.replyTo,
  1039. .topicRootId = realRoot,
  1040. },
  1041. entry.randomId,
  1042. std::move(entry.message),
  1043. std::move(entry.done),
  1044. std::move(entry.fail));
  1045. }
  1046. for (const auto &item : history->clientSideMessages()) {
  1047. const auto replace = [&](MsgId nowId) {
  1048. return (nowId == rootId.msg) ? realRoot : nowId;
  1049. };
  1050. if (item->topicRootId() == rootId.msg) {
  1051. item->setReplyFields(
  1052. replace(item->replyToId()),
  1053. realRoot,
  1054. true);
  1055. }
  1056. }
  1057. }
  1058. }
  1059. FullMsgId Histories::convertTopicReplyToId(
  1060. not_null<History*> history,
  1061. FullMsgId replyToId) const {
  1062. const auto id = (history->peer->id == replyToId.peer)
  1063. ? convertTopicReplyToId(history, replyToId.msg)
  1064. : replyToId.msg;
  1065. return { replyToId.peer, id };
  1066. }
  1067. MsgId Histories::convertTopicReplyToId(
  1068. not_null<History*> history,
  1069. MsgId replyToId) const {
  1070. if (!replyToId) {
  1071. return {};
  1072. }
  1073. const auto i = _createdTopicIds.find({ history->peer->id, replyToId });
  1074. return (i != end(_createdTopicIds)) ? i->second : replyToId;
  1075. }
  1076. void Histories::checkPostponed(not_null<History*> history, int id) {
  1077. if (const auto state = lookup(history)) {
  1078. finishSentRequest(history, state, id);
  1079. }
  1080. }
  1081. void Histories::cancelRequest(int id) {
  1082. if (!id) {
  1083. return;
  1084. } else if (_creatingTopicRequests.contains(id)) {
  1085. cancelDelayedByTopicRequest(id);
  1086. return;
  1087. }
  1088. const auto history = _historyByRequest.take(id);
  1089. if (!history) {
  1090. return;
  1091. }
  1092. const auto state = lookup(*history);
  1093. if (!state) {
  1094. return;
  1095. }
  1096. state->postponed.remove(id);
  1097. finishSentRequest(*history, state, id);
  1098. }
  1099. void Histories::cancelDelayedByTopicRequest(int id) {
  1100. for (auto &[rootId, messages] : _creatingTopics) {
  1101. messages.erase(
  1102. ranges::remove(messages, id, &DelayedByTopicMessage::requestId),
  1103. end(messages));
  1104. }
  1105. _creatingTopicRequests.remove(id);
  1106. }
  1107. void Histories::finishSentRequest(
  1108. not_null<History*> history,
  1109. not_null<State*> state,
  1110. int id) {
  1111. _historyByRequest.remove(id);
  1112. const auto i = state->sent.find(id);
  1113. if (i != end(state->sent)) {
  1114. session().api().request(i->second.id).cancel();
  1115. state->sent.erase(i);
  1116. }
  1117. if (!state->postponed.empty() && !postponeHistoryRequest(*state)) {
  1118. for (auto &[id, postponed] : base::take(state->postponed)) {
  1119. const auto requestId = postponed.generator([=, id=id] {
  1120. checkPostponed(history, id);
  1121. });
  1122. state->sent.emplace(id, SentRequest{
  1123. std::move(postponed.generator),
  1124. requestId,
  1125. RequestType::History
  1126. });
  1127. }
  1128. }
  1129. if (state->postponedRequestEntry && !postponeEntryRequest(*state)) {
  1130. const auto i = _dialogRequests.find(history);
  1131. Assert(i != end(_dialogRequests));
  1132. const auto &[j, ok] = _dialogRequestsPending.emplace(
  1133. history,
  1134. std::move(i->second));
  1135. Assert(ok);
  1136. _dialogRequests.erase(i);
  1137. state->postponedRequestEntry = false;
  1138. postponeRequestDialogEntries();
  1139. }
  1140. checkEmptyState(history);
  1141. }
  1142. Histories::State *Histories::lookup(not_null<History*> history) {
  1143. const auto i = _states.find(history);
  1144. return (i != end(_states)) ? &i->second : nullptr;
  1145. }
  1146. } // namespace Data