api_updates.cpp 80 KB

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