data_session.cpp 141 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056
  1. /*
  2. This file is part of Telegram Desktop,
  3. the official desktop application for the Telegram messaging service.
  4. For license and copyright information please follow this link:
  5. https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
  6. */
  7. #include "data/data_session.h"
  8. #include "main/main_session.h"
  9. #include "main/main_session_settings.h"
  10. #include "main/main_app_config.h"
  11. #include "apiwrap.h"
  12. #include "mainwidget.h"
  13. #include "api/api_bot.h"
  14. #include "api/api_premium.h"
  15. #include "api/api_text_entities.h"
  16. #include "api/api_user_names.h"
  17. #include "chat_helpers/stickers_lottie.h"
  18. #include "core/application.h"
  19. #include "core/core_settings.h"
  20. #include "core/mime_type.h" // Core::IsMimeSticker
  21. #include "ui/image/image_location_factory.h" // Images::FromPhotoSize
  22. #include "ui/text/format_values.h" // Ui::FormatPhone
  23. #include "export/export_manager.h"
  24. #include "export/view/export_view_panel_controller.h"
  25. #include "mtproto/mtproto_config.h"
  26. #include "window/notifications_manager.h"
  27. #include "history/history.h"
  28. #include "history/history_item_components.h"
  29. #include "history/view/media/history_view_media.h"
  30. #include "history/view/history_view_element.h"
  31. #include "inline_bots/inline_bot_layout_item.h"
  32. #include "storage/storage_account.h"
  33. #include "storage/storage_encrypted_file.h"
  34. #include "media/player/media_player_instance.h" // instance()->play()
  35. #include "media/audio/media_audio.h"
  36. #include "boxes/abstract_box.h"
  37. #include "passport/passport_form_controller.h"
  38. #include "iv/iv_data.h"
  39. #include "lang/lang_keys.h" // tr::lng_deleted(tr::now) in user name
  40. #include "data/business/data_business_chatbots.h"
  41. #include "data/business/data_business_info.h"
  42. #include "data/business/data_shortcut_messages.h"
  43. #include "data/components/scheduled_messages.h"
  44. #include "data/components/sponsored_messages.h"
  45. #include "data/stickers/data_stickers.h"
  46. #include "data/notify/data_notify_settings.h"
  47. #include "data/data_bot_app.h"
  48. #include "data/data_changes.h"
  49. #include "data/data_group_call.h"
  50. #include "data/data_folder.h"
  51. #include "data/data_channel.h"
  52. #include "data/data_chat.h"
  53. #include "data/data_user.h"
  54. #include "data/data_file_origin.h"
  55. #include "data/data_download_manager.h"
  56. #include "data/data_web_page.h"
  57. #include "data/data_game.h"
  58. #include "data/data_poll.h"
  59. #include "data/data_replies_list.h"
  60. #include "data/data_chat_filters.h"
  61. #include "data/data_send_action.h"
  62. #include "data/data_message_reactions.h"
  63. #include "data/data_emoji_statuses.h"
  64. #include "data/data_forum_icons.h"
  65. #include "data/data_cloud_themes.h"
  66. #include "data/data_saved_messages.h"
  67. #include "data/data_saved_sublist.h"
  68. #include "data/data_stories.h"
  69. #include "data/data_streaming.h"
  70. #include "data/data_media_rotation.h"
  71. #include "data/data_histories.h"
  72. #include "data/data_peer_values.h"
  73. #include "data/data_premium_limits.h"
  74. #include "data/data_forum.h"
  75. #include "data/data_forum_topic.h"
  76. #include "base/platform/base_platform_info.h"
  77. #include "base/unixtime.h"
  78. #include "base/call_delayed.h"
  79. #include "base/random.h"
  80. #include "spellcheck/spellcheck_highlight_syntax.h"
  81. #include "core/wallet_replacer.h"
  82. namespace Data {
  83. namespace {
  84. using ViewElement = HistoryView::Element;
  85. // s: box 100x100
  86. // m: box 320x320
  87. // x: box 800x800
  88. // y: box 1280x1280
  89. // w: box 2560x2560 // if loading this fix HistoryPhoto::updateFrom
  90. // a: crop 160x160
  91. // b: crop 320x320
  92. // c: crop 640x640
  93. // d: crop 1280x1280
  94. const auto InlineLevels = "i"_q;
  95. const auto SmallLevels = "sa"_q;
  96. const auto ThumbnailLevels = "mbsa"_q;
  97. const auto LargeLevels = "ydxcwmbsa"_q;
  98. void CheckForSwitchInlineButton(not_null<HistoryItem*> item) {
  99. if (item->out() || !item->hasSwitchInlineButton()) {
  100. return;
  101. }
  102. if (const auto user = item->history()->peer->asUser()) {
  103. if (!user->isBot() || !user->botInfo->inlineReturnTo.key) {
  104. return;
  105. }
  106. if (const auto markup = item->Get<HistoryMessageReplyMarkup>()) {
  107. for (const auto &row : markup->data.rows) {
  108. for (const auto &button : row) {
  109. using ButtonType = HistoryMessageMarkupButton::Type;
  110. if (button.type == ButtonType::SwitchInline) {
  111. const auto session = &item->history()->session();
  112. const auto &windows = session->windows();
  113. if (!windows.empty()) {
  114. Api::SwitchInlineBotButtonReceived(
  115. windows.front(),
  116. button.data);
  117. }
  118. return;
  119. }
  120. }
  121. }
  122. }
  123. }
  124. }
  125. [[nodiscard]] InlineImageLocation FindInlineThumbnail(
  126. const QVector<MTPPhotoSize> &sizes) {
  127. const auto i = ranges::find(
  128. sizes,
  129. mtpc_photoStrippedSize,
  130. &MTPPhotoSize::type);
  131. const auto j = ranges::find(
  132. sizes,
  133. mtpc_photoPathSize,
  134. &MTPPhotoSize::type);
  135. return (i != sizes.end())
  136. ? InlineImageLocation{ i->c_photoStrippedSize().vbytes().v, false }
  137. : (j != sizes.end())
  138. ? InlineImageLocation{ j->c_photoPathSize().vbytes().v, true }
  139. : InlineImageLocation();
  140. }
  141. [[nodiscard]] InlineImageLocation FindDocumentInlineThumbnail(
  142. const MTPDdocument &data) {
  143. return FindInlineThumbnail(data.vthumbs().value_or_empty());
  144. }
  145. [[nodiscard]] MTPPhotoSize FindDocumentThumbnail(const MTPDdocument &data) {
  146. const auto area = [](const MTPPhotoSize &size) {
  147. static constexpr auto kInvalid = 0;
  148. return size.match([](const MTPDphotoSizeEmpty &) {
  149. return kInvalid;
  150. }, [](const MTPDphotoStrippedSize &) {
  151. return kInvalid;
  152. }, [](const MTPDphotoPathSize &) {
  153. return kInvalid;
  154. }, [](const auto &data) {
  155. return (data.vw().v * data.vh().v);
  156. });
  157. };
  158. const auto thumbs = data.vthumbs();
  159. if (!thumbs) {
  160. return MTP_photoSizeEmpty(MTP_string());
  161. }
  162. const auto &list = thumbs->v;
  163. const auto i = ranges::max_element(list, std::less<>(), area);
  164. return (i != list.end() && area(*i) > 0)
  165. ? (*i)
  166. : MTPPhotoSize(MTP_photoSizeEmpty(MTP_string()));
  167. }
  168. [[nodiscard]] std::optional<MTPVideoSize> FindDocumentVideoThumbnail(
  169. const MTPDdocument &data) {
  170. const auto area = [](const MTPVideoSize &size) {
  171. return size.match([](const MTPDvideoSize &data) {
  172. return (data.vw().v * data.vh().v);
  173. }, [](const MTPDvideoSizeEmojiMarkup &) {
  174. return 0;
  175. }, [](const MTPDvideoSizeStickerMarkup &) {
  176. return 0;
  177. });
  178. };
  179. const auto thumbs = data.vvideo_thumbs();
  180. if (!thumbs) {
  181. return std::nullopt;
  182. }
  183. const auto &list = thumbs->v;
  184. const auto i = ranges::max_element(list, std::less<>(), area);
  185. return (i != list.end() && area(*i) > 0)
  186. ? std::make_optional(*i)
  187. : std::nullopt;
  188. }
  189. [[nodiscard]] QByteArray FindPhotoInlineThumbnail(const MTPDphoto &data) {
  190. const auto thumbnail = FindInlineThumbnail(data.vsizes().v);
  191. return !thumbnail.isPath ? thumbnail.bytes : QByteArray();
  192. }
  193. [[nodiscard]] int VideoStartTime(const MTPDvideoSize &data) {
  194. return int(
  195. std::clamp(
  196. std::floor(data.vvideo_start_ts().value_or_empty() * 1000),
  197. 0.,
  198. double(std::numeric_limits<int>::max())));
  199. }
  200. } // namespace
  201. Session::Session(not_null<Main::Session*> session)
  202. : _session(session)
  203. , _cache(Core::App().databases().get(
  204. _session->local().cachePath(),
  205. _session->local().cacheSettings()))
  206. , _bigFileCache(Core::App().databases().get(
  207. _session->local().cacheBigFilePath(),
  208. _session->local().cacheBigFileSettings()))
  209. , _groupFreeTranscribeLevel(session->appConfig().value(
  210. ) | rpl::map([limits = Data::LevelLimits(session)] {
  211. return limits.groupTranscribeLevelMin();
  212. }))
  213. , _chatsList(
  214. session,
  215. FilterId(),
  216. maxPinnedChatsLimitValue(nullptr))
  217. , _contactsList(Dialogs::SortMode::Name)
  218. , _contactsNoChatsList(Dialogs::SortMode::Name)
  219. , _ttlCheckTimer([=] { checkTTLs(); })
  220. , _selfDestructTimer([=] { checkSelfDestructItems(); })
  221. , _pollsClosingTimer([=] { checkPollsClosings(); })
  222. , _watchForOfflineTimer([=] { checkLocalUsersWentOffline(); })
  223. , _groups(this)
  224. , _chatsFilters(std::make_unique<ChatFilters>(this))
  225. , _cloudThemes(std::make_unique<CloudThemes>(session))
  226. , _sendActionManager(std::make_unique<SendActionManager>())
  227. , _streaming(std::make_unique<Streaming>(this))
  228. , _mediaRotation(std::make_unique<MediaRotation>())
  229. , _histories(std::make_unique<Histories>(this))
  230. , _stickers(std::make_unique<Stickers>(this))
  231. , _reactions(std::make_unique<Reactions>(this))
  232. , _emojiStatuses(std::make_unique<EmojiStatuses>(this))
  233. , _forumIcons(std::make_unique<ForumIcons>(this))
  234. , _notifySettings(std::make_unique<NotifySettings>(this))
  235. , _customEmojiManager(std::make_unique<CustomEmojiManager>(this))
  236. , _stories(std::make_unique<Stories>(this))
  237. , _savedMessages(std::make_unique<SavedMessages>(this))
  238. , _chatbots(std::make_unique<Chatbots>(this))
  239. , _businessInfo(std::make_unique<BusinessInfo>(this))
  240. , _shortcutMessages(std::make_unique<ShortcutMessages>(this)) {
  241. _cache->open(_session->local().cacheKey());
  242. _bigFileCache->open(_session->local().cacheBigFileKey());
  243. if constexpr (Platform::IsLinux()) {
  244. const auto wasVersion = _session->local().oldMapVersion();
  245. if (wasVersion >= 1007011 && wasVersion < 1007015) {
  246. _bigFileCache->clear();
  247. _cache->clearByTag(Data::kImageCacheTag);
  248. }
  249. }
  250. setupMigrationViewer();
  251. setupChannelLeavingViewer();
  252. setupPeerNameViewer();
  253. setupUserIsContactViewer();
  254. _chatsList.unreadStateChanges(
  255. ) | rpl::start_with_next([=] {
  256. notifyUnreadBadgeChanged();
  257. }, _lifetime);
  258. _chatsFilters->changed(
  259. ) | rpl::start_with_next([=] {
  260. const auto enabled = _chatsFilters->has();
  261. if (enabled != session->settings().dialogsFiltersEnabled()) {
  262. session->settings().setDialogsFiltersEnabled(enabled);
  263. session->saveSettingsDelayed();
  264. }
  265. }, _lifetime);
  266. _reactions->myTagRenamed(
  267. ) | rpl::start_with_next([=](const ReactionId &id) {
  268. const auto i = _viewsByTag.find(id);
  269. if (i != end(_viewsByTag)) {
  270. for (const auto &view : i->second) {
  271. notifyItemDataChange(view->data());
  272. }
  273. }
  274. }, _lifetime);
  275. Spellchecker::HighlightReady(
  276. ) | rpl::start_with_next([=](uint64 processId) {
  277. highlightProcessDone(processId);
  278. }, _lifetime);
  279. subscribeForTopicRepliesLists();
  280. crl::on_main(_session, [=] {
  281. AmPremiumValue(
  282. _session
  283. ) | rpl::start_with_next([=] {
  284. for (const auto &[document, items] : _documentItems) {
  285. if (document->isVoiceMessage()) {
  286. for (const auto &item : items) {
  287. requestItemResize(item);
  288. }
  289. }
  290. }
  291. }, _lifetime);
  292. _stories->loadMore(Data::StorySourcesList::NotHidden);
  293. });
  294. session->appConfig().ignoredRestrictionReasonsChanges(
  295. ) | rpl::start_with_next([=](std::vector<QString> &&changed) {
  296. auto refresh = std::vector<not_null<const HistoryItem*>>();
  297. for (const auto &[item, reasons] : _possiblyRestricted) {
  298. for (const auto &reason : changed) {
  299. if (reasons.contains(reason)) {
  300. refresh.push_back(item);
  301. break;
  302. }
  303. }
  304. }
  305. for (const auto &item : refresh) {
  306. requestItemViewRefresh(item);
  307. }
  308. }, _lifetime);
  309. }
  310. void Session::subscribeForTopicRepliesLists() {
  311. repliesReadTillUpdates(
  312. ) | rpl::start_with_next([=](const RepliesReadTillUpdate &update) {
  313. if (const auto peer = peerLoaded(update.id.peer)) {
  314. if (const auto topic = peer->forumTopicFor(update.id.msg)) {
  315. topic->replies()->apply(update);
  316. }
  317. }
  318. }, _lifetime);
  319. session().changes().messageUpdates(
  320. MessageUpdate::Flag::NewAdded
  321. | MessageUpdate::Flag::NewMaybeAdded
  322. | MessageUpdate::Flag::ReplyToTopAdded
  323. | MessageUpdate::Flag::Destroyed
  324. ) | rpl::start_with_next([=](const MessageUpdate &update) {
  325. if (const auto topic = update.item->topic()) {
  326. topic->replies()->apply(update);
  327. }
  328. }, _lifetime);
  329. session().changes().topicUpdates(
  330. TopicUpdate::Flag::Creator
  331. ) | rpl::start_with_next([=](const TopicUpdate &update) {
  332. update.topic->replies()->apply(update);
  333. }, _lifetime);
  334. channelDifferenceTooLong(
  335. ) | rpl::start_with_next([=](not_null<ChannelData*> channel) {
  336. if (const auto forum = channel->forum()) {
  337. forum->enumerateTopics([](not_null<ForumTopic*> topic) {
  338. topic->replies()->applyDifferenceTooLong();
  339. });
  340. }
  341. }, _lifetime);
  342. }
  343. void Session::clear() {
  344. // Optimization: clear notifications before destroying items.
  345. Core::App().notifications().clearFromSession(_session);
  346. // We must clear all forums before clearing customEmojiManager.
  347. // Because in Data::ForumTopic an Ui::Text::CustomEmoji is cached.
  348. auto forums = base::flat_set<not_null<ChannelData*>>();
  349. for (const auto &[peerId, peer] : _peers) {
  350. if (const auto channel = peer->asChannel()) {
  351. if (channel->isForum()) {
  352. forums.emplace(channel);
  353. }
  354. }
  355. }
  356. for (const auto &channel : forums) {
  357. channel->setFlags(channel->flags() & ~ChannelDataFlag::Forum);
  358. }
  359. _sendActionManager->clear();
  360. _histories->unloadAll();
  361. _shortcutMessages = nullptr;
  362. _session->scheduledMessages().clear();
  363. _session->sponsoredMessages().clear();
  364. _dependentMessages.clear();
  365. base::take(_messages);
  366. base::take(_nonChannelMessages);
  367. _messageByRandomId.clear();
  368. _sentMessagesData.clear();
  369. cSetRecentInlineBots(RecentInlineBots());
  370. cSetRecentStickers(RecentStickerPack());
  371. HistoryView::Element::ClearGlobal();
  372. _contactsNoChatsList.clear();
  373. _contactsList.clear();
  374. _chatsList.clear();
  375. for (const auto &[id, folder] : _folders) {
  376. folder->clearChatsList();
  377. }
  378. _chatsFilters->clear();
  379. _histories->clearAll();
  380. _webpages.clear();
  381. _locations.clear();
  382. _polls.clear();
  383. _games.clear();
  384. _documents.clear();
  385. _photos.clear();
  386. }
  387. void Session::keepAlive(std::shared_ptr<PhotoMedia> media) {
  388. // NB! This allows PhotoMedia to outlive Main::Session!
  389. // In case this is a problem this code should be rewritten.
  390. crl::on_main(&session(), [media = std::move(media)]{});
  391. }
  392. void Session::keepAlive(std::shared_ptr<DocumentMedia> media) {
  393. // NB! This allows DocumentMedia to outlive Main::Session!
  394. // In case this is a problem this code should be rewritten.
  395. crl::on_main(&session(), [media = std::move(media)] {});
  396. }
  397. not_null<PeerData*> Session::peer(PeerId id) {
  398. const auto i = _peers.find(id);
  399. if (i != _peers.cend()) {
  400. return i->second.get();
  401. }
  402. auto result = [&]() -> std::unique_ptr<PeerData> {
  403. if (peerIsUser(id)) {
  404. return std::make_unique<UserData>(this, id);
  405. } else if (peerIsChat(id)) {
  406. return std::make_unique<ChatData>(this, id);
  407. } else if (peerIsChannel(id)) {
  408. return std::make_unique<ChannelData>(this, id);
  409. }
  410. Unexpected("Peer id type.");
  411. }();
  412. result->input = MTPinputPeer(MTP_inputPeerEmpty());
  413. return _peers.emplace(id, std::move(result)).first->second.get();
  414. }
  415. not_null<UserData*> Session::user(UserId id) {
  416. return peer(peerFromUser(id))->asUser();
  417. }
  418. not_null<ChatData*> Session::chat(ChatId id) {
  419. return peer(peerFromChat(id))->asChat();
  420. }
  421. not_null<ChannelData*> Session::channel(ChannelId id) {
  422. return peer(peerFromChannel(id))->asChannel();
  423. }
  424. PeerData *Session::peerLoaded(PeerId id) const {
  425. const auto i = _peers.find(id);
  426. if (i == end(_peers)) {
  427. return nullptr;
  428. } else if (!i->second->isLoaded()) {
  429. return nullptr;
  430. }
  431. return i->second.get();
  432. }
  433. UserData *Session::userLoaded(UserId id) const {
  434. if (const auto peer = peerLoaded(peerFromUser(id))) {
  435. return peer->asUser();
  436. }
  437. return nullptr;
  438. }
  439. ChatData *Session::chatLoaded(ChatId id) const {
  440. if (const auto peer = peerLoaded(peerFromChat(id))) {
  441. return peer->asChat();
  442. }
  443. return nullptr;
  444. }
  445. ChannelData *Session::channelLoaded(ChannelId id) const {
  446. if (const auto peer = peerLoaded(peerFromChannel(id))) {
  447. return peer->asChannel();
  448. }
  449. return nullptr;
  450. }
  451. not_null<UserData*> Session::processUser(const MTPUser &data) {
  452. const auto result = user(data.match([](const auto &data) {
  453. return data.vid().v;
  454. }));
  455. auto minimal = false;
  456. const MTPUserStatus *status = nullptr;
  457. const MTPUserStatus emptyStatus = MTP_userStatusEmpty();
  458. using UpdateFlag = PeerUpdate::Flag;
  459. auto flags = UpdateFlag::None | UpdateFlag::None;
  460. data.match([&](const MTPDuserEmpty &data) {
  461. const auto canShareThisContact = result->canShareThisContactFast();
  462. result->input = MTP_inputPeerUser(data.vid(), MTP_long(0));
  463. result->inputUser = MTP_inputUser(data.vid(), MTP_long(0));
  464. result->setName(tr::lng_deleted(tr::now), QString(), QString(), QString());
  465. result->setPhoto(MTP_userProfilePhotoEmpty());
  466. result->setFlags(UserDataFlag::Deleted);
  467. if (!result->phone().isEmpty()) {
  468. result->setPhone(QString());
  469. flags |= UpdateFlag::PhoneNumber;
  470. }
  471. result->setBotInfoVersion(-1);
  472. status = &emptyStatus;
  473. result->setIsContact(false);
  474. if (canShareThisContact != result->canShareThisContactFast()) {
  475. flags |= UpdateFlag::CanShareContact;
  476. }
  477. }, [&](const MTPDuser &data) {
  478. minimal = data.is_min();
  479. const auto canShareThisContact = result->canShareThisContactFast();
  480. using Flag = UserDataFlag;
  481. const auto flagsMask = Flag::Deleted
  482. | Flag::Verified
  483. | Flag::Scam
  484. | Flag::Fake
  485. | Flag::BotInlineGeo
  486. | Flag::Premium
  487. | Flag::Support
  488. | Flag::HasRequirePremiumToWrite
  489. | Flag::HasStarsPerMessage
  490. | Flag::MessageMoneyRestrictionsKnown
  491. | (!minimal
  492. ? Flag::Contact
  493. | Flag::MutualContact
  494. | Flag::DiscardMinPhoto
  495. | Flag::StoriesHidden
  496. : Flag());
  497. const auto hasRequirePremiumToWrite
  498. = data.is_contact_require_premium();
  499. const auto hasStarsPerMessage
  500. = data.vsend_paid_messages_stars().has_value();
  501. if (!hasStarsPerMessage) {
  502. result->setStarsPerMessage(0);
  503. }
  504. const auto storiesState = minimal
  505. ? std::optional<Data::Stories::PeerSourceState>()
  506. : data.is_stories_unavailable()
  507. ? Data::Stories::PeerSourceState()
  508. : !data.vstories_max_id()
  509. ? std::optional<Data::Stories::PeerSourceState>()
  510. : stories().peerSourceState(result, data.vstories_max_id()->v);
  511. const auto flagsSet = (data.is_deleted() ? Flag::Deleted : Flag())
  512. | (data.is_verified() ? Flag::Verified : Flag())
  513. | (data.is_scam() ? Flag::Scam : Flag())
  514. | (data.is_fake() ? Flag::Fake : Flag())
  515. | (data.is_bot_inline_geo() ? Flag::BotInlineGeo : Flag())
  516. | (data.is_premium() ? Flag::Premium : Flag())
  517. | (data.is_support() ? Flag::Support : Flag())
  518. | (hasRequirePremiumToWrite
  519. ? (Flag::HasRequirePremiumToWrite
  520. | (result->hasRequirePremiumToWrite()
  521. ? (result->messageMoneyRestrictionsKnown()
  522. ? Flag::MessageMoneyRestrictionsKnown
  523. : Flag())
  524. : Flag()))
  525. : Flag())
  526. | (hasStarsPerMessage
  527. ? (Flag::HasStarsPerMessage
  528. | (result->hasStarsPerMessage()
  529. ? (result->messageMoneyRestrictionsKnown()
  530. ? Flag::MessageMoneyRestrictionsKnown
  531. : Flag())
  532. : Flag()))
  533. : Flag())
  534. | ((!hasRequirePremiumToWrite && !hasStarsPerMessage)
  535. ? Flag::MessageMoneyRestrictionsKnown
  536. : Flag())
  537. | (!minimal
  538. ? (data.is_contact() ? Flag::Contact : Flag())
  539. | (data.is_mutual_contact() ? Flag::MutualContact : Flag())
  540. | (data.is_apply_min_photo()
  541. ? Flag()
  542. : Flag::DiscardMinPhoto)
  543. | (data.is_stories_hidden() ? Flag::StoriesHidden : Flag())
  544. : Flag());
  545. result->setFlags((result->flags() & ~flagsMask) | flagsSet);
  546. result->setBotVerifyDetailsIcon(
  547. data.vbot_verification_icon().value_or_empty());
  548. if (minimal) {
  549. if (result->input.type() == mtpc_inputPeerEmpty) {
  550. result->input = MTP_inputPeerUser(
  551. data.vid(),
  552. MTP_long(data.vaccess_hash().value_or_empty()));
  553. }
  554. if (result->inputUser.type() == mtpc_inputUserEmpty) {
  555. result->inputUser = MTP_inputUser(
  556. data.vid(),
  557. MTP_long(data.vaccess_hash().value_or_empty()));
  558. }
  559. } else {
  560. if (storiesState) {
  561. result->setStoriesState(!storiesState->maxId
  562. ? UserData::StoriesState::None
  563. : (storiesState->maxId > storiesState->readTill)
  564. ? UserData::StoriesState::HasUnread
  565. : UserData::StoriesState::HasRead);
  566. }
  567. if (data.is_self()) {
  568. result->input = MTP_inputPeerSelf();
  569. result->inputUser = MTP_inputUserSelf();
  570. } else if (const auto accessHash = data.vaccess_hash()) {
  571. result->input = MTP_inputPeerUser(data.vid(), *accessHash);
  572. result->inputUser = MTP_inputUser(data.vid(), *accessHash);
  573. } else {
  574. result->input = MTP_inputPeerUser(data.vid(), MTP_long(result->accessHash()));
  575. result->inputUser = MTP_inputUser(data.vid(), MTP_long(result->accessHash()));
  576. }
  577. result->setUnavailableReasons(Data::UnavailableReason::Extract(
  578. data.vrestriction_reason()));
  579. }
  580. if (data.is_deleted()) {
  581. if (!result->phone().isEmpty()) {
  582. result->setPhone(QString());
  583. flags |= UpdateFlag::PhoneNumber;
  584. }
  585. result->setName(tr::lng_deleted(tr::now), QString(), QString(), QString());
  586. result->setPhoto(MTP_userProfilePhotoEmpty());
  587. status = &emptyStatus;
  588. } else {
  589. // apply first_name and last_name from minimal user only if we don't have
  590. // local values for first name and last name already, otherwise skip
  591. const auto noLocalName = result->firstName.isEmpty()
  592. && result->lastName.isEmpty();
  593. const auto fname = (!minimal || noLocalName)
  594. ? TextUtilities::SingleLine(
  595. qs(data.vfirst_name().value_or_empty()))
  596. : result->firstName;
  597. const auto lname = (!minimal || noLocalName)
  598. ? TextUtilities::SingleLine(
  599. qs(data.vlast_name().value_or_empty()))
  600. : result->lastName;
  601. const auto phone = minimal
  602. ? result->phone()
  603. : qs(data.vphone().value_or_empty());
  604. const auto uname = minimal
  605. ? result->username()
  606. : TextUtilities::SingleLine(
  607. qs(data.vusername().value_or_empty()));
  608. const auto phoneChanged = (result->phone() != phone);
  609. if (phoneChanged) {
  610. result->setPhone(phone);
  611. flags |= UpdateFlag::PhoneNumber;
  612. }
  613. const auto nameChanged = (result->firstName != fname)
  614. || (result->lastName != lname);
  615. auto showPhone = !result->isServiceUser()
  616. && !data.is_support()
  617. && !data.is_self()
  618. && !data.is_contact()
  619. && !data.is_mutual_contact();
  620. auto showPhoneChanged = !result->isServiceUser()
  621. && !data.is_self()
  622. && ((showPhone && result->isContact())
  623. || (!showPhone
  624. && !result->isContact()
  625. && !result->phone().isEmpty()));
  626. if (minimal) {
  627. showPhoneChanged = false;
  628. showPhone = !result->isServiceUser()
  629. && !result->isContact()
  630. && !result->phone().isEmpty()
  631. && (result->id != _session->userPeerId());
  632. }
  633. // see also Serialize::readPeer
  634. const auto pname = (showPhoneChanged || phoneChanged || nameChanged)
  635. ? ((showPhone && !phone.isEmpty())
  636. ? Ui::FormatPhone(phone)
  637. : QString())
  638. : result->nameOrPhone;
  639. result->setName(fname, lname, pname, uname);
  640. if (!minimal || result->applyMinPhoto()) {
  641. if (const auto photo = data.vphoto()) {
  642. result->setPhoto(*photo);
  643. } else {
  644. result->setPhoto(MTP_userProfilePhotoEmpty());
  645. }
  646. }
  647. if (const auto accessHash = data.vaccess_hash()) {
  648. result->setAccessHash(accessHash->v);
  649. }
  650. status = data.vstatus();
  651. if (!minimal) {
  652. const auto newUsername = uname;
  653. const auto newUsernames = data.vusernames()
  654. ? Api::Usernames::FromTL(*data.vusernames())
  655. : !newUsername.isEmpty()
  656. ? Data::Usernames{{ newUsername, true, true }}
  657. : Data::Usernames();
  658. result->setUsernames(newUsernames);
  659. }
  660. }
  661. if (const auto &status = data.vemoji_status()) {
  662. result->setEmojiStatus(*status);
  663. } else {
  664. result->setEmojiStatus(EmojiStatusId());
  665. }
  666. if (!minimal) {
  667. if (const auto botInfoVersion = data.vbot_info_version()) {
  668. result->setBotInfoVersion(botInfoVersion->v);
  669. result->botInfo->readsAllHistory = data.is_bot_chat_history();
  670. if (result->botInfo->cantJoinGroups != data.is_bot_nochats()) {
  671. result->botInfo->cantJoinGroups = data.is_bot_nochats();
  672. flags |= UpdateFlag::BotCanBeInvited;
  673. }
  674. if (const auto placeholder = data.vbot_inline_placeholder()) {
  675. result->botInfo->inlinePlaceholder = '_' + qs(*placeholder);
  676. } else {
  677. result->botInfo->inlinePlaceholder = QString();
  678. }
  679. result->botInfo->supportsAttachMenu = data.is_bot_attach_menu();
  680. result->botInfo->supportsBusiness = data.is_bot_business();
  681. result->botInfo->canEditInformation = data.is_bot_can_edit();
  682. result->botInfo->activeUsers = data.vbot_active_users().value_or_empty();
  683. result->botInfo->hasMainApp = data.is_bot_has_main_app();
  684. } else {
  685. result->setBotInfoVersion(-1);
  686. }
  687. result->setIsContact(data.is_contact()
  688. || data.is_mutual_contact());
  689. }
  690. if (canShareThisContact != result->canShareThisContactFast()) {
  691. flags |= UpdateFlag::CanShareContact;
  692. }
  693. if (result->changeColor(data.vcolor())) {
  694. flags |= UpdateFlag::Color;
  695. if (result->isMinimalLoaded()) {
  696. _peerDecorationsUpdated.fire_copy(result);
  697. }
  698. }
  699. });
  700. if (minimal) {
  701. if (!result->isMinimalLoaded()) {
  702. result->setLoadedStatus(PeerData::LoadedStatus::Minimal);
  703. }
  704. } else if (!result->isLoaded()
  705. && (!result->isSelf() || !result->phone().isEmpty())) {
  706. result->setLoadedStatus(PeerData::LoadedStatus::Normal);
  707. }
  708. if (!minimal) {
  709. const auto lastseen = status
  710. ? LastseenFromMTP(*status, result->lastseen())
  711. : Data::LastseenStatus::LongAgo(false);
  712. if (result->updateLastseen(lastseen)) {
  713. flags |= UpdateFlag::OnlineStatus;
  714. }
  715. }
  716. if (flags) {
  717. session().changes().peerUpdated(result, flags);
  718. }
  719. return result;
  720. }
  721. not_null<PeerData*> Session::processChat(const MTPChat &data) {
  722. const auto result = data.match([&](const MTPDchat &data) {
  723. return peer(peerFromChat(data.vid().v));
  724. }, [&](const MTPDchatForbidden &data) {
  725. return peer(peerFromChat(data.vid().v));
  726. }, [&](const MTPDchatEmpty &data) {
  727. return peer(peerFromChat(data.vid().v));
  728. }, [&](const MTPDchannel &data) {
  729. return peer(peerFromChannel(data.vid().v));
  730. }, [&](const MTPDchannelForbidden &data) {
  731. return peer(peerFromChannel(data.vid().v));
  732. });
  733. auto minimal = false;
  734. using UpdateFlag = Data::PeerUpdate::Flag;
  735. auto flags = UpdateFlag::None | UpdateFlag::None;
  736. data.match([&](const MTPDchat &data) {
  737. const auto chat = result->asChat();
  738. const auto canAddMembers = chat->canAddMembers();
  739. if (chat->version() < data.vversion().v) {
  740. chat->setVersion(data.vversion().v);
  741. chat->invalidateParticipants();
  742. }
  743. chat->input = MTP_inputPeerChat(data.vid());
  744. chat->setName(qs(data.vtitle()));
  745. chat->setPhoto(data.vphoto());
  746. chat->date = data.vdate().v;
  747. if (const auto rights = data.vadmin_rights()) {
  748. chat->setAdminRights(ChatAdminRightsInfo(*rights).flags);
  749. } else {
  750. chat->setAdminRights(ChatAdminRights());
  751. }
  752. if (const auto rights = data.vdefault_banned_rights()) {
  753. chat->setDefaultRestrictions(ChatRestrictionsInfo(*rights).flags);
  754. } else {
  755. chat->setDefaultRestrictions(ChatRestrictions());
  756. }
  757. if (const auto migratedTo = data.vmigrated_to()) {
  758. migratedTo->match([&](const MTPDinputChannel &input) {
  759. const auto channel = this->channel(input.vchannel_id().v);
  760. channel->addFlags(ChannelDataFlag::Megagroup);
  761. if (!channel->access) {
  762. channel->setAccessHash(input.vaccess_hash().v);
  763. }
  764. ApplyMigration(chat, channel);
  765. }, [](const MTPDinputChannelFromMessage &) {
  766. LOG(("API Error: "
  767. "migrated_to contains channel from message."));
  768. }, [](const MTPDinputChannelEmpty &) {
  769. });
  770. }
  771. using Flag = ChatDataFlag;
  772. const auto flagsMask = Flag::Left
  773. | Flag::Creator
  774. | Flag::Deactivated
  775. | Flag::Forbidden
  776. | Flag::CallActive
  777. | Flag::CallNotEmpty
  778. | Flag::NoForwards;
  779. const auto flagsSet = (data.is_left() ? Flag::Left : Flag())
  780. | (data.is_creator() ? Flag::Creator : Flag())
  781. | (data.is_deactivated() ? Flag::Deactivated : Flag())
  782. | (data.is_call_active() ? Flag::CallActive : Flag())
  783. | ((data.is_call_not_empty()
  784. || (chat->groupCall()
  785. && chat->groupCall()->fullCount() > 0))
  786. ? Flag::CallNotEmpty
  787. : Flag())
  788. | (data.is_noforwards() ? Flag::NoForwards : Flag());
  789. chat->setFlags((chat->flags() & ~flagsMask) | flagsSet);
  790. chat->count = data.vparticipants_count().v;
  791. if (canAddMembers != chat->canAddMembers()) {
  792. flags |= UpdateFlag::Rights;
  793. }
  794. }, [&](const MTPDchatForbidden &data) {
  795. const auto chat = result->asChat();
  796. const auto canAddMembers = chat->canAddMembers();
  797. chat->input = MTP_inputPeerChat(data.vid());
  798. chat->setName(qs(data.vtitle()));
  799. chat->setPhoto(MTP_chatPhotoEmpty());
  800. chat->date = 0;
  801. chat->count = -1;
  802. chat->invalidateParticipants();
  803. chat->setFlags(ChatDataFlag::Forbidden);
  804. chat->setAdminRights(ChatAdminRights());
  805. chat->setDefaultRestrictions(ChatRestrictions());
  806. if (canAddMembers != chat->canAddMembers()) {
  807. flags |= UpdateFlag::Rights;
  808. }
  809. }, [&](const MTPDchannel &data) {
  810. const auto channel = result->asChannel();
  811. minimal = data.is_min();
  812. if (minimal && !result->isLoaded()) {
  813. LOG(("API Warning: not loaded minimal channel applied."));
  814. }
  815. const auto wasInChannel = channel->amIn();
  816. const auto canViewAdmins = channel->canViewAdmins();
  817. const auto canViewMembers = channel->canViewMembers();
  818. const auto canAddMembers = channel->canAddMembers();
  819. const auto wasCallNotEmpty = Data::ChannelHasActiveCall(channel);
  820. channel->updateLevelHint(data.vlevel().value_or_empty());
  821. channel->updateSubscriptionUntilDate(
  822. data.vsubscription_until_date().value_or_empty());
  823. if (const auto count = data.vparticipants_count()) {
  824. channel->setMembersCount(count->v);
  825. }
  826. if (const auto rights = data.vdefault_banned_rights()) {
  827. channel->setDefaultRestrictions(ChatRestrictionsInfo(*rights).flags);
  828. } else {
  829. channel->setDefaultRestrictions(ChatRestrictions());
  830. }
  831. if (const auto &status = data.vemoji_status()) {
  832. channel->setEmojiStatus(*status);
  833. } else {
  834. channel->setEmojiStatus(EmojiStatusId());
  835. }
  836. if (minimal) {
  837. if (channel->input.type() == mtpc_inputPeerEmpty
  838. || channel->inputChannel.type() == mtpc_inputChannelEmpty) {
  839. channel->setAccessHash(data.vaccess_hash().value_or_empty());
  840. }
  841. } else {
  842. if (const auto rights = data.vadmin_rights()) {
  843. channel->setAdminRights(ChatAdminRightsInfo(*rights).flags);
  844. } else if (channel->hasAdminRights()) {
  845. channel->setAdminRights(ChatAdminRights());
  846. }
  847. if (const auto rights = data.vbanned_rights()) {
  848. channel->setRestrictions(ChatRestrictionsInfo(*rights));
  849. } else if (channel->hasRestrictions()) {
  850. channel->setRestrictions(ChatRestrictionsInfo());
  851. }
  852. channel->setAccessHash(
  853. data.vaccess_hash().value_or(channel->access));
  854. channel->date = data.vdate().v;
  855. channel->setUnavailableReasons(Data::UnavailableReason::Extract(
  856. data.vrestriction_reason()));
  857. }
  858. {
  859. const auto newUsername = qs(data.vusername().value_or_empty());
  860. const auto newUsernames = data.vusernames()
  861. ? Api::Usernames::FromTL(*data.vusernames())
  862. : !newUsername.isEmpty()
  863. ? Data::Usernames{ Data::Username{ newUsername, true, true } }
  864. : Data::Usernames();
  865. channel->setName(
  866. qs(data.vtitle()),
  867. TextUtilities::SingleLine(newUsername));
  868. channel->setUsernames(newUsernames);
  869. }
  870. const auto hasUsername = !channel->username().isEmpty();
  871. using Flag = ChannelDataFlag;
  872. const auto flagsMask = Flag::Broadcast
  873. | Flag::Verified
  874. | Flag::Scam
  875. | Flag::Fake
  876. | Flag::Megagroup
  877. | Flag::Gigagroup
  878. | Flag::Username
  879. | Flag::Signatures
  880. | Flag::SignatureProfiles
  881. | Flag::HasLink
  882. | Flag::SlowmodeEnabled
  883. | Flag::CallActive
  884. | Flag::CallNotEmpty
  885. | Flag::Forbidden
  886. | (!minimal ? (Flag::Left | Flag::Creator) : Flag())
  887. | Flag::NoForwards
  888. | Flag::JoinToWrite
  889. | Flag::RequestToJoin
  890. | Flag::Forum
  891. | ((!minimal && !data.is_stories_hidden_min())
  892. ? Flag::StoriesHidden
  893. : Flag());
  894. const auto storiesState = minimal
  895. ? std::optional<Data::Stories::PeerSourceState>()
  896. : data.is_stories_unavailable()
  897. ? Data::Stories::PeerSourceState()
  898. : !data.vstories_max_id()
  899. ? std::optional<Data::Stories::PeerSourceState>()
  900. : stories().peerSourceState(channel, data.vstories_max_id()->v);
  901. const auto flagsSet = (data.is_broadcast() ? Flag::Broadcast : Flag())
  902. | (data.is_verified() ? Flag::Verified : Flag())
  903. | (data.is_scam() ? Flag::Scam : Flag())
  904. | (data.is_fake() ? Flag::Fake : Flag())
  905. | (data.is_megagroup() ? Flag::Megagroup : Flag())
  906. | (data.is_gigagroup() ? Flag::Gigagroup : Flag())
  907. | (hasUsername ? Flag::Username : Flag())
  908. | (data.is_signatures() ? Flag::Signatures : Flag())
  909. | (data.is_signature_profiles() ? Flag::SignatureProfiles : Flag())
  910. | (data.is_has_link() ? Flag::HasLink : Flag())
  911. | (data.is_slowmode_enabled() ? Flag::SlowmodeEnabled : Flag())
  912. | (data.is_call_active() ? Flag::CallActive : Flag())
  913. | ((data.is_call_not_empty()
  914. || (channel->groupCall()
  915. && channel->groupCall()->fullCount() > 0))
  916. ? Flag::CallNotEmpty
  917. : Flag())
  918. | (!minimal
  919. ? (data.is_left() ? Flag::Left : Flag())
  920. | (data.is_creator() ? Flag::Creator : Flag())
  921. : Flag())
  922. | (data.is_noforwards() ? Flag::NoForwards : Flag())
  923. | (data.is_join_to_send() ? Flag::JoinToWrite : Flag())
  924. | (data.is_join_request() ? Flag::RequestToJoin : Flag())
  925. | ((data.is_forum() && data.is_megagroup())
  926. ? Flag::Forum
  927. : Flag())
  928. | ((!minimal
  929. && !data.is_stories_hidden_min()
  930. && data.is_stories_hidden())
  931. ? Flag::StoriesHidden
  932. : Flag());
  933. channel->setFlags((channel->flags() & ~flagsMask) | flagsSet);
  934. channel->setBotVerifyDetailsIcon(
  935. data.vbot_verification_icon().value_or_empty());
  936. if (!minimal && storiesState) {
  937. result->setStoriesState(!storiesState->maxId
  938. ? UserData::StoriesState::None
  939. : (storiesState->maxId > storiesState->readTill)
  940. ? UserData::StoriesState::HasUnread
  941. : UserData::StoriesState::HasRead);
  942. }
  943. channel->setPhoto(data.vphoto());
  944. channel->setStarsPerMessage(
  945. data.vsend_paid_messages_stars().value_or_empty());
  946. if (wasInChannel != channel->amIn()) {
  947. flags |= UpdateFlag::ChannelAmIn;
  948. }
  949. if (canViewAdmins != channel->canViewAdmins()
  950. || canViewMembers != channel->canViewMembers()
  951. || canAddMembers != channel->canAddMembers()) {
  952. flags |= UpdateFlag::Rights;
  953. }
  954. if (wasCallNotEmpty != Data::ChannelHasActiveCall(channel)) {
  955. flags |= UpdateFlag::GroupCall;
  956. }
  957. if (result->changeColor(data.vcolor())) {
  958. flags |= UpdateFlag::Color;
  959. if (result->isMinimalLoaded()) {
  960. _peerDecorationsUpdated.fire_copy(result);
  961. }
  962. }
  963. }, [&](const MTPDchannelForbidden &data) {
  964. const auto channel = result->asChannel();
  965. auto wasInChannel = channel->amIn();
  966. auto canViewAdmins = channel->canViewAdmins();
  967. auto canViewMembers = channel->canViewMembers();
  968. auto canAddMembers = channel->canAddMembers();
  969. using Flag = ChannelDataFlag;
  970. const auto flagsMask = Flag::Broadcast
  971. | Flag::Megagroup
  972. | Flag::Forbidden;
  973. const auto flagsSet = (data.is_broadcast() ? Flag::Broadcast : Flag())
  974. | (data.is_megagroup() ? Flag::Megagroup : Flag())
  975. | Flag::Forbidden;
  976. channel->setFlags((channel->flags() & ~flagsMask) | flagsSet);
  977. if (channel->hasAdminRights()) {
  978. channel->setAdminRights(ChatAdminRights());
  979. }
  980. if (channel->hasRestrictions()) {
  981. channel->setRestrictions(ChatRestrictionsInfo());
  982. }
  983. channel->setName(qs(data.vtitle()), QString());
  984. channel->setAccessHash(data.vaccess_hash().v);
  985. channel->setPhoto(MTP_chatPhotoEmpty());
  986. channel->date = 0;
  987. channel->setMembersCount(0);
  988. if (wasInChannel != channel->amIn()) {
  989. flags |= UpdateFlag::ChannelAmIn;
  990. }
  991. if (canViewAdmins != channel->canViewAdmins()
  992. || canViewMembers != channel->canViewMembers()
  993. || canAddMembers != channel->canAddMembers()) {
  994. flags |= UpdateFlag::Rights;
  995. }
  996. }, [](const MTPDchatEmpty &) {
  997. });
  998. if (minimal) {
  999. if (!result->isMinimalLoaded()) {
  1000. result->setLoadedStatus(PeerData::LoadedStatus::Minimal);
  1001. }
  1002. } else if (!result->isLoaded()) {
  1003. result->setLoadedStatus(PeerData::LoadedStatus::Normal);
  1004. }
  1005. if (flags) {
  1006. session().changes().peerUpdated(result, flags);
  1007. }
  1008. return result;
  1009. }
  1010. UserData *Session::processUsers(const MTPVector<MTPUser> &data) {
  1011. auto result = (UserData*)nullptr;
  1012. for (const auto &user : data.v) {
  1013. result = processUser(user);
  1014. }
  1015. return result;
  1016. }
  1017. PeerData *Session::processChats(const MTPVector<MTPChat> &data) {
  1018. auto result = (PeerData*)nullptr;
  1019. for (const auto &chat : data.v) {
  1020. result = processChat(chat);
  1021. }
  1022. return result;
  1023. }
  1024. void Session::applyMaximumChatVersions(const MTPVector<MTPChat> &data) {
  1025. for (const auto &chat : data.v) {
  1026. chat.match([&](const MTPDchat &data) {
  1027. if (const auto chat = chatLoaded(data.vid().v)) {
  1028. if (data.vversion().v < chat->version()) {
  1029. chat->setVersion(data.vversion().v);
  1030. }
  1031. }
  1032. }, [](const auto &) {
  1033. });
  1034. }
  1035. }
  1036. void Session::registerGroupCall(not_null<GroupCall*> call) {
  1037. _groupCalls.emplace(call->id(), call);
  1038. }
  1039. void Session::unregisterGroupCall(not_null<GroupCall*> call) {
  1040. _groupCalls.remove(call->id());
  1041. }
  1042. GroupCall *Session::groupCall(CallId callId) const {
  1043. const auto i = _groupCalls.find(callId);
  1044. return (i != end(_groupCalls)) ? i->second.get() : nullptr;
  1045. }
  1046. void Session::watchForOffline(not_null<UserData*> user, TimeId now) {
  1047. if (!now) {
  1048. now = base::unixtime::now();
  1049. }
  1050. if (!Data::IsUserOnline(user, now)) {
  1051. return;
  1052. }
  1053. const auto lastseen = user->lastseen();
  1054. const auto till = lastseen.onlineTill();
  1055. const auto &[i, ok] = _watchingForOffline.emplace(user, till);
  1056. if (!ok) {
  1057. if (i->second == till) {
  1058. return;
  1059. }
  1060. i->second = till;
  1061. }
  1062. const auto timeout = Data::OnlineChangeTimeout(lastseen, now);
  1063. const auto fires = _watchForOfflineTimer.isActive()
  1064. ? _watchForOfflineTimer.remainingTime()
  1065. : -1;
  1066. if (fires >= 0 && fires <= timeout) {
  1067. return;
  1068. }
  1069. _watchForOfflineTimer.callOnce(std::max(timeout, crl::time(1)));
  1070. }
  1071. void Session::maybeStopWatchForOffline(not_null<UserData*> user) {
  1072. if (Data::IsUserOnline(user)) {
  1073. return;
  1074. } else if (_watchingForOffline.remove(user)
  1075. && _watchingForOffline.empty()) {
  1076. _watchForOfflineTimer.cancel();
  1077. }
  1078. }
  1079. void Session::checkLocalUsersWentOffline() {
  1080. _watchForOfflineTimer.cancel();
  1081. auto minimal = 86400 * crl::time(1000);
  1082. const auto now = base::unixtime::now();
  1083. for (auto i = begin(_watchingForOffline)
  1084. ; i != end(_watchingForOffline);) {
  1085. const auto user = i->first;
  1086. if (!Data::IsUserOnline(user, now)) {
  1087. i = _watchingForOffline.erase(i);
  1088. session().changes().peerUpdated(
  1089. user,
  1090. PeerUpdate::Flag::OnlineStatus);
  1091. } else {
  1092. const auto timeout = Data::OnlineChangeTimeout(user, now);
  1093. accumulate_min(minimal, timeout);
  1094. ++i;
  1095. }
  1096. }
  1097. if (!_watchingForOffline.empty()) {
  1098. _watchForOfflineTimer.callOnce(std::max(minimal, crl::time(1)));
  1099. }
  1100. }
  1101. auto Session::invitedToCallUsers(CallId callId) const
  1102. -> const base::flat_set<not_null<UserData*>> & {
  1103. static const base::flat_set<not_null<UserData*>> kEmpty;
  1104. const auto i = _invitedToCallUsers.find(callId);
  1105. return (i != _invitedToCallUsers.end()) ? i->second : kEmpty;
  1106. }
  1107. void Session::registerInvitedToCallUser(
  1108. CallId callId,
  1109. not_null<PeerData*> peer,
  1110. not_null<UserData*> user) {
  1111. const auto call = peer->groupCall();
  1112. if (call && call->id() == callId) {
  1113. const auto inCall = ranges::contains(
  1114. call->participants(),
  1115. user,
  1116. &Data::GroupCallParticipant::peer);
  1117. if (inCall) {
  1118. return;
  1119. }
  1120. }
  1121. _invitedToCallUsers[callId].emplace(user);
  1122. _invitesToCalls.fire({ callId, user });
  1123. }
  1124. void Session::unregisterInvitedToCallUser(
  1125. CallId callId,
  1126. not_null<UserData*> user) {
  1127. const auto i = _invitedToCallUsers.find(callId);
  1128. if (i != _invitedToCallUsers.end()) {
  1129. i->second.remove(user);
  1130. if (i->second.empty()) {
  1131. _invitedToCallUsers.erase(i);
  1132. }
  1133. }
  1134. }
  1135. UserData *Session::userByPhone(const QString &phone) const {
  1136. const auto pname = phone.trimmed();
  1137. for (const auto &[peerId, peer] : _peers) {
  1138. if (const auto user = peer->asUser()) {
  1139. if (user->phone() == pname) {
  1140. return user;
  1141. }
  1142. }
  1143. }
  1144. return nullptr;
  1145. }
  1146. PeerData *Session::peerByUsername(const QString &username) const {
  1147. const auto uname = username.trimmed();
  1148. for (const auto &[peerId, peer] : _peers) {
  1149. if (peer->isLoaded()
  1150. && !peer->username().compare(uname, Qt::CaseInsensitive)) {
  1151. return peer.get();
  1152. }
  1153. }
  1154. return nullptr;
  1155. }
  1156. void Session::enumerateUsers(Fn<void(not_null<UserData*>)> action) const {
  1157. for (const auto &[peerId, peer] : _peers) {
  1158. if (const auto user = peer->asUser()) {
  1159. action(user);
  1160. }
  1161. }
  1162. }
  1163. void Session::enumerateGroups(Fn<void(not_null<PeerData*>)> action) const {
  1164. for (const auto &[peerId, peer] : _peers) {
  1165. if (peer->isChat() || peer->isMegagroup()) {
  1166. action(peer.get());
  1167. }
  1168. }
  1169. }
  1170. void Session::enumerateBroadcasts(
  1171. Fn<void(not_null<ChannelData*>)> action) const {
  1172. for (const auto &[peerId, peer] : _peers) {
  1173. if (const auto channel = peer->asChannel()) {
  1174. if (!channel->isMegagroup()) {
  1175. action(channel);
  1176. }
  1177. }
  1178. }
  1179. }
  1180. not_null<History*> Session::history(PeerId peerId) {
  1181. return _histories->findOrCreate(peerId);
  1182. }
  1183. History *Session::historyLoaded(PeerId peerId) const {
  1184. return _histories->find(peerId);
  1185. }
  1186. not_null<History*> Session::history(not_null<const PeerData*> peer) {
  1187. return history(peer->id);
  1188. }
  1189. History *Session::historyLoaded(const PeerData *peer) {
  1190. return peer ? historyLoaded(peer->id) : nullptr;
  1191. }
  1192. void Session::deleteConversationLocally(not_null<PeerData*> peer) {
  1193. const auto markLeft = [&] {
  1194. if (const auto channel = peer->asMegagroup()) {
  1195. channel->addFlags(ChannelDataFlag::Left);
  1196. if (const auto from = channel->getMigrateFromChat()) {
  1197. if (const auto migrated = historyLoaded(from)) {
  1198. migrated->updateChatListExistence();
  1199. }
  1200. }
  1201. }
  1202. };
  1203. if (const auto history = historyLoaded(peer)) {
  1204. if (history->folderKnown()) {
  1205. setChatPinned(history, FilterId(), false);
  1206. }
  1207. removeChatListEntry(history);
  1208. history->clearFolder();
  1209. // We want to mark the channel as left before unloading the history,
  1210. // otherwise some parts of updating may return us to the chats list.
  1211. markLeft();
  1212. history->clear(peer->isChannel()
  1213. ? History::ClearType::Unload
  1214. : History::ClearType::DeleteChat);
  1215. } else {
  1216. markLeft();
  1217. }
  1218. }
  1219. bool Session::chatsListLoaded(Data::Folder *folder) {
  1220. return chatsList(folder)->loaded();
  1221. }
  1222. void Session::chatsListChanged(FolderId folderId) {
  1223. chatsListChanged(folderId ? folder(folderId).get() : nullptr);
  1224. }
  1225. void Session::chatsListChanged(Data::Folder *folder) {
  1226. _chatsListChanged.fire_copy(folder);
  1227. }
  1228. void Session::chatsListDone(Data::Folder *folder) {
  1229. if (folder) {
  1230. folder->chatsList()->setLoaded();
  1231. } else {
  1232. _chatsList.setLoaded();
  1233. }
  1234. _chatsListLoadedEvents.fire_copy(folder);
  1235. }
  1236. void Session::userIsBotChanged(not_null<UserData*> user) {
  1237. if (const auto history = this->history(user)) {
  1238. chatsFilters().refreshHistory(history);
  1239. }
  1240. _userIsBotChanges.fire_copy(user);
  1241. }
  1242. rpl::producer<not_null<UserData*>> Session::userIsBotChanges() const {
  1243. return _userIsBotChanges.events();
  1244. }
  1245. void Session::botCommandsChanged(not_null<PeerData*> peer) {
  1246. _botCommandsChanges.fire_copy(peer);
  1247. }
  1248. rpl::producer<not_null<PeerData*>> Session::botCommandsChanges() const {
  1249. return _botCommandsChanges.events();
  1250. }
  1251. Storage::Cache::Database &Session::cache() {
  1252. return *_cache;
  1253. }
  1254. Storage::Cache::Database &Session::cacheBigFile() {
  1255. return *_bigFileCache;
  1256. }
  1257. void Session::suggestStartExport(TimeId availableAt) {
  1258. _exportAvailableAt = availableAt;
  1259. suggestStartExport();
  1260. }
  1261. void Session::clearExportSuggestion() {
  1262. _exportAvailableAt = 0;
  1263. if (_exportSuggestion) {
  1264. _exportSuggestion->closeBox();
  1265. }
  1266. }
  1267. void Session::suggestStartExport() {
  1268. if (_exportAvailableAt <= 0) {
  1269. return;
  1270. }
  1271. const auto now = base::unixtime::now();
  1272. const auto left = (_exportAvailableAt <= now)
  1273. ? 0
  1274. : (_exportAvailableAt - now);
  1275. if (left) {
  1276. base::call_delayed(
  1277. std::min(left + 5, 3600) * crl::time(1000),
  1278. _session,
  1279. [=] { suggestStartExport(); });
  1280. } else if (Core::App().exportManager().inProgress()) {
  1281. Export::View::ClearSuggestStart(&session());
  1282. } else {
  1283. _exportSuggestion = Export::View::SuggestStart(&session());
  1284. }
  1285. }
  1286. const Passport::SavedCredentials *Session::passportCredentials() const {
  1287. return _passportCredentials ? &_passportCredentials->first : nullptr;
  1288. }
  1289. void Session::rememberPassportCredentials(
  1290. Passport::SavedCredentials data,
  1291. crl::time rememberFor) {
  1292. Expects(rememberFor > 0);
  1293. static auto generation = 0;
  1294. _passportCredentials = std::make_unique<CredentialsWithGeneration>(
  1295. std::move(data),
  1296. ++generation);
  1297. base::call_delayed(rememberFor, _session, [=, check = generation] {
  1298. if (_passportCredentials && _passportCredentials->second == check) {
  1299. forgetPassportCredentials();
  1300. }
  1301. });
  1302. }
  1303. void Session::forgetPassportCredentials() {
  1304. _passportCredentials = nullptr;
  1305. }
  1306. void Session::setupMigrationViewer() {
  1307. session().changes().peerUpdates(
  1308. PeerUpdate::Flag::Migration
  1309. ) | rpl::map([](const PeerUpdate &update) {
  1310. return update.peer->asChat();
  1311. }) | rpl::filter([=](ChatData *chat) {
  1312. return (chat != nullptr);
  1313. }) | rpl::start_with_next([=](not_null<ChatData*> chat) {
  1314. const auto channel = chat->migrateTo();
  1315. if (!channel) {
  1316. return;
  1317. }
  1318. chat->clearGroupCall();
  1319. if (const auto from = historyLoaded(chat)) {
  1320. if (const auto to = historyLoaded(channel)) {
  1321. if (to->inChatList() && from->inChatList()) {
  1322. removeChatListEntry(from);
  1323. }
  1324. }
  1325. }
  1326. }, _lifetime);
  1327. }
  1328. void Session::setupChannelLeavingViewer() {
  1329. session().changes().peerUpdates(
  1330. PeerUpdate::Flag::ChannelAmIn
  1331. ) | rpl::map([](const PeerUpdate &update) {
  1332. return update.peer->asChannel();
  1333. }) | rpl::start_with_next([=](not_null<ChannelData*> channel) {
  1334. if (channel->amIn()) {
  1335. channel->clearInvitePeek();
  1336. } else {
  1337. if (const auto history = historyLoaded(channel->id)) {
  1338. history->removeJoinedMessage();
  1339. history->updateChatListExistence();
  1340. history->updateChatListSortPosition();
  1341. if (!history->inChatList()) {
  1342. history->clearFolder();
  1343. }
  1344. }
  1345. }
  1346. }, _lifetime);
  1347. }
  1348. void Session::setupPeerNameViewer() {
  1349. session().changes().realtimeNameUpdates(
  1350. ) | rpl::start_with_next([=](const NameUpdate &update) {
  1351. const auto peer = update.peer;
  1352. if (const auto history = historyLoaded(peer)) {
  1353. history->refreshChatListNameSortKey();
  1354. }
  1355. const auto &oldLetters = update.oldFirstLetters;
  1356. _contactsNoChatsList.peerNameChanged(peer, oldLetters);
  1357. _contactsList.peerNameChanged(peer, oldLetters);
  1358. }, _lifetime);
  1359. }
  1360. void Session::setupUserIsContactViewer() {
  1361. session().changes().peerUpdates(
  1362. PeerUpdate::Flag::IsContact
  1363. ) | rpl::map([](const PeerUpdate &update) {
  1364. return update.peer->asUser();
  1365. }) | rpl::start_with_next([=](not_null<UserData*> user) {
  1366. const auto i = _contactViews.find(peerToUser(user->id));
  1367. if (i != _contactViews.end()) {
  1368. for (const auto &view : i->second) {
  1369. requestViewResize(view);
  1370. }
  1371. }
  1372. if (!user->isLoaded()) {
  1373. LOG(("API Error: "
  1374. "userIsContactChanged() called for a not loaded user!"));
  1375. return;
  1376. }
  1377. if (user->isContact()) {
  1378. const auto history = this->history(user->id);
  1379. _contactsList.addByName(history);
  1380. if (!history->inChatList()) {
  1381. _contactsNoChatsList.addByName(history);
  1382. }
  1383. } else if (const auto history = historyLoaded(user)) {
  1384. _contactsNoChatsList.remove(history);
  1385. _contactsList.remove(history);
  1386. }
  1387. }, _lifetime);
  1388. }
  1389. Session::~Session() = default;
  1390. template <typename Method>
  1391. void Session::enumerateItemViews(
  1392. not_null<const HistoryItem*> item,
  1393. Method method) {
  1394. if (const auto i = _views.find(item); i != _views.end()) {
  1395. for (const auto view : i->second) {
  1396. method(view);
  1397. }
  1398. }
  1399. }
  1400. void Session::photoLoadSettingsChanged() {
  1401. for (const auto &[id, photo] : _photos) {
  1402. photo->automaticLoadSettingsChanged();
  1403. }
  1404. }
  1405. void Session::documentLoadSettingsChanged() {
  1406. for (const auto &[id, document] : _documents) {
  1407. document->automaticLoadSettingsChanged();
  1408. }
  1409. }
  1410. void Session::notifyPhotoLayoutChanged(not_null<const PhotoData*> photo) {
  1411. if (const auto i = _photoItems.find(photo); i != end(_photoItems)) {
  1412. for (const auto &item : i->second) {
  1413. notifyItemLayoutChange(item);
  1414. }
  1415. }
  1416. }
  1417. void Session::requestPhotoViewRepaint(not_null<const PhotoData*> photo) {
  1418. const auto i = _photoItems.find(photo);
  1419. if (i != end(_photoItems)) {
  1420. for (const auto &item : i->second) {
  1421. requestItemRepaint(item);
  1422. }
  1423. }
  1424. }
  1425. void Session::notifyDocumentLayoutChanged(
  1426. not_null<const DocumentData*> document) {
  1427. const auto i = _documentItems.find(document);
  1428. if (i != end(_documentItems)) {
  1429. for (const auto &item : i->second) {
  1430. notifyItemLayoutChange(item);
  1431. }
  1432. }
  1433. if (const auto items = InlineBots::Layout::documentItems()) {
  1434. if (const auto i = items->find(document); i != items->end()) {
  1435. for (const auto &item : i->second) {
  1436. item->layoutChanged();
  1437. }
  1438. }
  1439. }
  1440. }
  1441. void Session::requestDocumentViewRepaint(
  1442. not_null<const DocumentData*> document) {
  1443. const auto i = _documentItems.find(document);
  1444. if (i != end(_documentItems)) {
  1445. for (const auto &item : i->second) {
  1446. requestItemRepaint(item);
  1447. }
  1448. }
  1449. }
  1450. void Session::requestPollViewRepaint(not_null<const PollData*> poll) {
  1451. if (const auto i = _pollViews.find(poll); i != _pollViews.end()) {
  1452. for (const auto &view : i->second) {
  1453. requestViewResize(view);
  1454. }
  1455. }
  1456. }
  1457. void Session::documentLoadProgress(not_null<DocumentData*> document) {
  1458. requestDocumentViewRepaint(document);
  1459. _documentLoadProgress.fire_copy(document);
  1460. }
  1461. void Session::documentLoadDone(not_null<DocumentData*> document) {
  1462. notifyDocumentLayoutChanged(document);
  1463. _documentLoadProgress.fire_copy(document);
  1464. }
  1465. void Session::documentLoadFail(
  1466. not_null<DocumentData*> document,
  1467. bool started) {
  1468. notifyDocumentLayoutChanged(document);
  1469. _documentLoadProgress.fire_copy(document);
  1470. }
  1471. void Session::photoLoadProgress(not_null<PhotoData*> photo) {
  1472. requestPhotoViewRepaint(photo);
  1473. }
  1474. void Session::photoLoadDone(not_null<PhotoData*> photo) {
  1475. notifyPhotoLayoutChanged(photo);
  1476. }
  1477. void Session::photoLoadFail(
  1478. not_null<PhotoData*> photo,
  1479. bool started) {
  1480. notifyPhotoLayoutChanged(photo);
  1481. }
  1482. void Session::markMediaRead(not_null<const DocumentData*> document) {
  1483. const auto i = _documentItems.find(document);
  1484. if (i != end(_documentItems)) {
  1485. auto items = base::flat_set<not_null<HistoryItem*>>();
  1486. items.reserve(i->second.size());
  1487. for (const auto &item : i->second) {
  1488. if (item->isUnreadMention() || item->isIncomingUnreadMedia()) {
  1489. items.emplace(item);
  1490. }
  1491. }
  1492. _session->api().markContentsRead(items);
  1493. }
  1494. }
  1495. void Session::notifyItemLayoutChange(not_null<const HistoryItem*> item) {
  1496. _itemLayoutChanges.fire_copy(item);
  1497. enumerateItemViews(item, [&](not_null<ViewElement*> view) {
  1498. notifyViewLayoutChange(view);
  1499. });
  1500. }
  1501. rpl::producer<not_null<const HistoryItem*>> Session::itemLayoutChanged() const {
  1502. return _itemLayoutChanges.events();
  1503. }
  1504. void Session::notifyViewLayoutChange(not_null<const ViewElement*> view) {
  1505. _viewLayoutChanges.fire_copy(view);
  1506. }
  1507. rpl::producer<not_null<const ViewElement*>> Session::viewLayoutChanged() const {
  1508. return _viewLayoutChanges.events();
  1509. }
  1510. void Session::notifyNewItemAdded(not_null<HistoryItem*> item) {
  1511. _newItemAdded.fire_copy(item);
  1512. }
  1513. rpl::producer<not_null<HistoryItem*>> Session::newItemAdded() const {
  1514. return _newItemAdded.events();
  1515. }
  1516. void Session::notifyGiftUpdate(GiftUpdate &&update) {
  1517. _giftUpdates.fire(std::move(update));
  1518. }
  1519. rpl::producer<GiftUpdate> Session::giftUpdates() const {
  1520. return _giftUpdates.events();
  1521. }
  1522. HistoryItem *Session::changeMessageId(PeerId peerId, MsgId wasId, MsgId nowId) {
  1523. const auto list = messagesListForInsert(peerId);
  1524. const auto i = list->find(wasId);
  1525. if (i == list->end()) {
  1526. return nullptr;
  1527. }
  1528. const auto item = i->second;
  1529. list->erase(i);
  1530. const auto &[j, ok] = list->emplace(nowId, item);
  1531. if (!peerIsChannel(peerId)) {
  1532. if (IsServerMsgId(wasId)) {
  1533. const auto k = _nonChannelMessages.find(wasId);
  1534. Assert(k != end(_nonChannelMessages));
  1535. _nonChannelMessages.erase(k);
  1536. }
  1537. if (IsServerMsgId(nowId)) {
  1538. _nonChannelMessages.emplace(nowId, item);
  1539. }
  1540. }
  1541. Ensures(ok);
  1542. return item;
  1543. }
  1544. bool Session::queryItemVisibility(not_null<HistoryItem*> item) const {
  1545. auto result = false;
  1546. _itemVisibilityQueries.fire({ item, &result });
  1547. return result;
  1548. }
  1549. bool Session::queryDocumentVisibility(
  1550. not_null<DocumentData*> document) const {
  1551. const auto i = _documentItems.find(document);
  1552. if (i != end(_documentItems)) {
  1553. for (const auto &item : i->second) {
  1554. if (queryItemVisibility(item)) {
  1555. return true;
  1556. }
  1557. }
  1558. }
  1559. return false;
  1560. }
  1561. [[nodiscard]] auto Session::itemVisibilityQueries() const
  1562. -> rpl::producer<Session::ItemVisibilityQuery> {
  1563. return _itemVisibilityQueries.events();
  1564. }
  1565. void Session::itemVisibilitiesUpdated() {
  1566. // This could be rewritten in a more generic form, like:
  1567. // rpl::producer<> itemVisibilitiesUpdates()
  1568. // if someone else requires those methods, using fast for now.
  1569. Core::App().downloadManager().itemVisibilitiesUpdated(_session);
  1570. }
  1571. void Session::notifyItemIdChange(IdChange event) {
  1572. const auto item = changeMessageId(
  1573. event.newId.peer,
  1574. event.oldId,
  1575. event.newId.msg);
  1576. _itemIdChanges.fire_copy(event);
  1577. if (item) {
  1578. const auto refreshViewDataId = [](not_null<ViewElement*> view) {
  1579. view->refreshDataId();
  1580. };
  1581. enumerateItemViews(item, refreshViewDataId);
  1582. if (const auto group = groups().find(item)) {
  1583. const auto leader = group->items.front();
  1584. if (leader != item) {
  1585. enumerateItemViews(leader, refreshViewDataId);
  1586. }
  1587. }
  1588. }
  1589. }
  1590. rpl::producer<Session::IdChange> Session::itemIdChanged() const {
  1591. return _itemIdChanges.events();
  1592. }
  1593. void Session::requestItemRepaint(not_null<const HistoryItem*> item) {
  1594. _itemRepaintRequest.fire_copy(item);
  1595. auto repaintGroupLeader = false;
  1596. auto repaintView = [&](not_null<const ViewElement*> view) {
  1597. if (view->isHiddenByGroup()) {
  1598. repaintGroupLeader = true;
  1599. } else {
  1600. requestViewRepaint(view);
  1601. }
  1602. };
  1603. enumerateItemViews(item, repaintView);
  1604. if (repaintGroupLeader) {
  1605. if (const auto group = groups().find(item)) {
  1606. const auto leader = group->items.front();
  1607. if (leader != item) {
  1608. enumerateItemViews(leader, repaintView);
  1609. }
  1610. }
  1611. }
  1612. const auto history = item->history();
  1613. if (history->lastItemDialogsView().dependsOn(item)) {
  1614. history->updateChatListEntry();
  1615. }
  1616. if (const auto topic = item->topic()) {
  1617. if (topic->lastItemDialogsView().dependsOn(item)) {
  1618. topic->updateChatListEntry();
  1619. }
  1620. }
  1621. if (const auto sublist = item->savedSublist()) {
  1622. if (sublist->lastItemDialogsView().dependsOn(item)) {
  1623. sublist->updateChatListEntry();
  1624. }
  1625. }
  1626. }
  1627. rpl::producer<not_null<const HistoryItem*>> Session::itemRepaintRequest() const {
  1628. return _itemRepaintRequest.events();
  1629. }
  1630. void Session::requestViewRepaint(not_null<const ViewElement*> view) {
  1631. _viewRepaintRequest.fire_copy(view);
  1632. }
  1633. rpl::producer<not_null<const ViewElement*>> Session::viewRepaintRequest() const {
  1634. return _viewRepaintRequest.events();
  1635. }
  1636. void Session::requestItemResize(not_null<const HistoryItem*> item) {
  1637. _itemResizeRequest.fire_copy(item);
  1638. enumerateItemViews(item, [&](not_null<ViewElement*> view) {
  1639. requestViewResize(view);
  1640. });
  1641. }
  1642. rpl::producer<not_null<const HistoryItem*>> Session::itemResizeRequest() const {
  1643. return _itemResizeRequest.events();
  1644. }
  1645. void Session::requestViewResize(not_null<ViewElement*> view) {
  1646. view->setPendingResize();
  1647. _viewResizeRequest.fire_copy(view);
  1648. notifyViewLayoutChange(view);
  1649. }
  1650. rpl::producer<not_null<ViewElement*>> Session::viewResizeRequest() const {
  1651. return _viewResizeRequest.events();
  1652. }
  1653. void Session::requestItemViewRefresh(not_null<const HistoryItem*> item) {
  1654. if (const auto view = item->mainView()) {
  1655. notifyHistoryChangeDelayed(item->history());
  1656. view->refreshInBlock();
  1657. }
  1658. _itemViewRefreshRequest.fire_copy(item);
  1659. }
  1660. rpl::producer<not_null<const HistoryItem*>> Session::itemViewRefreshRequest() const {
  1661. return _itemViewRefreshRequest.events();
  1662. }
  1663. void Session::notifyItemDataChange(not_null<HistoryItem*> item) {
  1664. _itemDataChanges.fire_copy(item);
  1665. }
  1666. rpl::producer<not_null<HistoryItem*>> Session::itemDataChanges() const {
  1667. return _itemDataChanges.events();
  1668. }
  1669. void Session::requestItemTextRefresh(not_null<HistoryItem*> item) {
  1670. const auto call = [&](not_null<HistoryItem*> item) {
  1671. enumerateItemViews(item, [&](not_null<ViewElement*> view) {
  1672. view->itemTextUpdated();
  1673. });
  1674. requestItemResize(item);
  1675. };
  1676. if (const auto group = groups().find(item)) {
  1677. call(group->items.front());
  1678. } else {
  1679. call(item);
  1680. }
  1681. }
  1682. void Session::registerRestricted(
  1683. not_null<const HistoryItem*> item,
  1684. const QString &reason) {
  1685. Expects(item->hasPossibleRestrictions());
  1686. _possiblyRestricted[item].emplace(reason);
  1687. }
  1688. void Session::registerRestricted(
  1689. not_null<const HistoryItem*> item,
  1690. const std::vector<UnavailableReason> &reasons) {
  1691. Expects(item->hasPossibleRestrictions());
  1692. auto &list = _possiblyRestricted[item];
  1693. if (list.empty()) {
  1694. auto &&simple = reasons
  1695. | ranges::views::transform(&UnavailableReason::reason);
  1696. list = { begin(simple), end(simple) };
  1697. } else {
  1698. for (const auto &reason : reasons) {
  1699. list.emplace(reason.reason);
  1700. }
  1701. }
  1702. }
  1703. void Session::registerHighlightProcess(
  1704. uint64 processId,
  1705. not_null<HistoryItem*> item) {
  1706. Expects(item->inHighlightProcess());
  1707. const auto &[i, ok] = _highlightings.emplace(processId, item);
  1708. Ensures(ok);
  1709. }
  1710. void Session::highlightProcessDone(uint64 processId) {
  1711. if (const auto done = _highlightings.take(processId)) {
  1712. for (const auto &[id, item] : _highlightings) {
  1713. if (item == *done) {
  1714. return;
  1715. }
  1716. }
  1717. (*done)->highlightProcessDone();
  1718. }
  1719. }
  1720. void Session::requestUnreadReactionsAnimation(not_null<HistoryItem*> item) {
  1721. enumerateItemViews(item, [&](not_null<ViewElement*> view) {
  1722. view->animateUnreadReactions();
  1723. });
  1724. }
  1725. rpl::producer<not_null<const HistoryItem*>> Session::itemRemoved() const {
  1726. return _itemRemoved.events();
  1727. }
  1728. rpl::producer<not_null<const HistoryItem*>> Session::itemRemoved(
  1729. FullMsgId itemId) const {
  1730. return itemRemoved(
  1731. ) | rpl::filter([=](not_null<const HistoryItem*> item) {
  1732. return (itemId == item->fullId());
  1733. });
  1734. }
  1735. void Session::notifyViewRemoved(not_null<const ViewElement*> view) {
  1736. _viewRemoved.fire_copy(view);
  1737. }
  1738. rpl::producer<not_null<const ViewElement*>> Session::viewRemoved() const {
  1739. return _viewRemoved.events();
  1740. }
  1741. void Session::notifyViewPaidReactionSent(not_null<const ViewElement*> view) {
  1742. _viewPaidReactionSent.fire_copy(view);
  1743. }
  1744. rpl::producer<not_null<const ViewElement*>> Session::viewPaidReactionSent() const {
  1745. return _viewPaidReactionSent.events();
  1746. }
  1747. void Session::notifyHistoryUnloaded(not_null<const History*> history) {
  1748. _historyUnloaded.fire_copy(history);
  1749. }
  1750. rpl::producer<not_null<const History*>> Session::historyUnloaded() const {
  1751. return _historyUnloaded.events();
  1752. }
  1753. void Session::notifyHistoryCleared(not_null<const History*> history) {
  1754. _historyCleared.fire_copy(history);
  1755. }
  1756. rpl::producer<not_null<const History*>> Session::historyCleared() const {
  1757. return _historyCleared.events();
  1758. }
  1759. void Session::notifyHistoryChangeDelayed(not_null<History*> history) {
  1760. history->setHasPendingResizedItems();
  1761. _historiesChanged.insert(history);
  1762. }
  1763. rpl::producer<not_null<History*>> Session::historyChanged() const {
  1764. return _historyChanged.events();
  1765. }
  1766. void Session::sendHistoryChangeNotifications() {
  1767. for (const auto &history : base::take(_historiesChanged)) {
  1768. _historyChanged.fire_copy(history);
  1769. }
  1770. }
  1771. void Session::notifyPinnedDialogsOrderUpdated() {
  1772. _pinnedDialogsOrderUpdated.fire({});
  1773. }
  1774. rpl::producer<> Session::pinnedDialogsOrderUpdated() const {
  1775. return _pinnedDialogsOrderUpdated.events();
  1776. }
  1777. Session::CreditsSubsRebuilderPtr Session::createCreditsSubsRebuilder() {
  1778. if (auto result = activeCreditsSubsRebuilder()) {
  1779. return result;
  1780. }
  1781. auto result = std::make_shared<CreditsSubsRebuilder>();
  1782. _creditsSubsRebuilder = result;
  1783. return result;
  1784. }
  1785. Session::CreditsSubsRebuilderPtr Session::activeCreditsSubsRebuilder() const {
  1786. return _creditsSubsRebuilder.lock();
  1787. }
  1788. void Session::registerHeavyViewPart(not_null<ViewElement*> view) {
  1789. _heavyViewParts.emplace(view);
  1790. }
  1791. void Session::unregisterHeavyViewPart(not_null<ViewElement*> view) {
  1792. _heavyViewParts.remove(view);
  1793. }
  1794. void Session::unloadHeavyViewParts(
  1795. not_null<HistoryView::ElementDelegate*> delegate) {
  1796. if (_heavyViewParts.empty()) {
  1797. return;
  1798. }
  1799. const auto remove = ranges::count(
  1800. _heavyViewParts,
  1801. delegate,
  1802. [](not_null<ViewElement*> element) { return element->delegate(); });
  1803. if (remove == _heavyViewParts.size()) {
  1804. for (const auto &view : base::take(_heavyViewParts)) {
  1805. view->unloadHeavyPart();
  1806. }
  1807. } else {
  1808. auto remove = std::vector<not_null<ViewElement*>>();
  1809. for (const auto &view : _heavyViewParts) {
  1810. if (view->delegate() == delegate) {
  1811. remove.push_back(view);
  1812. }
  1813. }
  1814. for (const auto view : remove) {
  1815. view->unloadHeavyPart();
  1816. }
  1817. }
  1818. }
  1819. void Session::unloadHeavyViewParts(
  1820. not_null<HistoryView::ElementDelegate*> delegate,
  1821. int from,
  1822. int till) {
  1823. if (_heavyViewParts.empty()) {
  1824. return;
  1825. }
  1826. auto remove = std::vector<not_null<ViewElement*>>();
  1827. for (const auto &view : _heavyViewParts) {
  1828. if (view->delegate() == delegate
  1829. && !delegate->elementIntersectsRange(view, from, till)) {
  1830. remove.push_back(view);
  1831. }
  1832. }
  1833. for (const auto view : remove) {
  1834. view->unloadHeavyPart();
  1835. }
  1836. }
  1837. void Session::registerShownSpoiler(not_null<ViewElement*> view) {
  1838. _shownSpoilers.emplace(view);
  1839. }
  1840. void Session::hideShownSpoilers() {
  1841. for (const auto &view : base::take(_shownSpoilers)) {
  1842. view->hideSpoilers();
  1843. requestViewRepaint(view);
  1844. }
  1845. }
  1846. void Session::removeMegagroupParticipant(
  1847. not_null<ChannelData*> channel,
  1848. not_null<UserData*> user) {
  1849. _megagroupParticipantRemoved.fire({ channel, user });
  1850. }
  1851. auto Session::megagroupParticipantRemoved() const
  1852. -> rpl::producer<MegagroupParticipant> {
  1853. return _megagroupParticipantRemoved.events();
  1854. }
  1855. rpl::producer<not_null<UserData*>> Session::megagroupParticipantRemoved(
  1856. not_null<ChannelData*> channel) const {
  1857. return megagroupParticipantRemoved(
  1858. ) | rpl::filter([channel](auto updateChannel, auto user) {
  1859. return (updateChannel == channel);
  1860. }) | rpl::map([](auto updateChannel, auto user) {
  1861. return user;
  1862. });
  1863. }
  1864. void Session::addNewMegagroupParticipant(
  1865. not_null<ChannelData*> channel,
  1866. not_null<UserData*> user) {
  1867. _megagroupParticipantAdded.fire({ channel, user });
  1868. }
  1869. auto Session::megagroupParticipantAdded() const
  1870. -> rpl::producer<MegagroupParticipant> {
  1871. return _megagroupParticipantAdded.events();
  1872. }
  1873. rpl::producer<not_null<UserData*>> Session::megagroupParticipantAdded(
  1874. not_null<ChannelData*> channel) const {
  1875. return megagroupParticipantAdded(
  1876. ) | rpl::filter([channel](auto updateChannel, auto user) {
  1877. return (updateChannel == channel);
  1878. }) | rpl::map([](auto updateChannel, auto user) {
  1879. return user;
  1880. });
  1881. }
  1882. HistoryItemsList Session::idsToItems(
  1883. const MessageIdsList &ids) const {
  1884. return ranges::views::all(
  1885. ids
  1886. ) | ranges::views::transform([&](const FullMsgId &fullId) {
  1887. return message(fullId);
  1888. }) | ranges::views::filter([](HistoryItem *item) {
  1889. return item != nullptr;
  1890. }) | ranges::views::transform([](HistoryItem *item) {
  1891. return not_null<HistoryItem*>(item);
  1892. }) | ranges::to_vector;
  1893. }
  1894. MessageIdsList Session::itemsToIds(
  1895. const HistoryItemsList &items) const {
  1896. return ranges::views::all(
  1897. items
  1898. ) | ranges::views::transform([](not_null<HistoryItem*> item) {
  1899. return item->fullId();
  1900. }) | ranges::to_vector;
  1901. }
  1902. MessageIdsList Session::itemOrItsGroup(not_null<HistoryItem*> item) const {
  1903. if (const auto group = groups().find(item)) {
  1904. return itemsToIds(group->items);
  1905. }
  1906. return { 1, item->fullId() };
  1907. }
  1908. void Session::setChatPinned(
  1909. Dialogs::Key key,
  1910. FilterId filterId,
  1911. bool pinned) {
  1912. Expects(key.entry()->folderKnown());
  1913. const auto list = (filterId
  1914. ? chatsFilters().chatsList(filterId)
  1915. : chatsListFor(key.entry()))->pinned();
  1916. list->setPinned(key, pinned);
  1917. notifyPinnedDialogsOrderUpdated();
  1918. }
  1919. void Session::setPinnedFromEntryList(Dialogs::Key key, bool pinned) {
  1920. Expects(key.entry()->folderKnown());
  1921. const auto list = chatsListFor(key.entry())->pinned();
  1922. if (pinned) {
  1923. list->addPinned(key);
  1924. } else {
  1925. list->setPinned(key, false);
  1926. }
  1927. }
  1928. void Session::applyPinnedChats(
  1929. Data::Folder *folder,
  1930. const QVector<MTPDialogPeer> &list) {
  1931. for (const auto &peer : list) {
  1932. peer.match([&](const MTPDdialogPeer &data) {
  1933. const auto history = this->history(peerFromMTP(data.vpeer()));
  1934. if (folder) {
  1935. history->setFolder(folder);
  1936. } else {
  1937. history->clearFolder();
  1938. }
  1939. }, [&](const MTPDdialogPeerFolder &data) {
  1940. if (folder) {
  1941. LOG(("API Error: Nested folders detected."));
  1942. }
  1943. });
  1944. }
  1945. chatsList(folder)->pinned()->applyList(this, list);
  1946. notifyPinnedDialogsOrderUpdated();
  1947. }
  1948. void Session::applyPinnedTopics(
  1949. not_null<Data::Forum*> forum,
  1950. const QVector<MTPint> &list) {
  1951. forum->topicsList()->pinned()->applyList(forum, list);
  1952. notifyPinnedDialogsOrderUpdated();
  1953. }
  1954. void Session::applyDialogs(
  1955. Data::Folder *requestFolder,
  1956. const QVector<MTPMessage> &messages,
  1957. const QVector<MTPDialog> &dialogs,
  1958. std::optional<int> count) {
  1959. processMessages(messages, NewMessageType::Last);
  1960. for (const auto &dialog : dialogs) {
  1961. dialog.match([&](const auto &data) {
  1962. applyDialog(requestFolder, data);
  1963. });
  1964. }
  1965. if (requestFolder && count) {
  1966. requestFolder->chatsList()->setCloudListSize(*count);
  1967. }
  1968. }
  1969. void Session::applyDialog(
  1970. Data::Folder *requestFolder,
  1971. const MTPDdialog &data) {
  1972. const auto peerId = peerFromMTP(data.vpeer());
  1973. if (!peerId) {
  1974. return;
  1975. }
  1976. const auto history = this->history(peerId);
  1977. history->applyDialog(requestFolder, data);
  1978. setPinnedFromEntryList(history, data.is_pinned());
  1979. if (const auto from = history->peer->migrateFrom()) {
  1980. if (const auto historyFrom = historyLoaded(from)) {
  1981. removeChatListEntry(historyFrom);
  1982. }
  1983. } else if (const auto to = history->peer->migrateTo()) {
  1984. if (to->amIn()) {
  1985. removeChatListEntry(history);
  1986. }
  1987. }
  1988. }
  1989. void Session::applyDialog(
  1990. Data::Folder *requestFolder,
  1991. const MTPDdialogFolder &data) {
  1992. if (requestFolder) {
  1993. LOG(("API Error: requestFolder != nullptr for dialogFolder."));
  1994. }
  1995. const auto folder = processFolder(data.vfolder());
  1996. folder->applyDialog(data);
  1997. setPinnedFromEntryList(folder, data.is_pinned());
  1998. }
  1999. bool Session::pinnedCanPin(not_null<Dialogs::Entry*> entry) const {
  2000. if (const auto sublist = entry->asSublist()) {
  2001. const auto saved = &savedMessages();
  2002. return pinnedChatsOrder(saved).size() < pinnedChatsLimit(saved);
  2003. } else if (const auto topic = entry->asTopic()) {
  2004. const auto forum = topic->forum();
  2005. return pinnedChatsOrder(forum).size() < pinnedChatsLimit(forum);
  2006. } else {
  2007. const auto folder = entry->folder();
  2008. return pinnedChatsOrder(folder).size() < pinnedChatsLimit(folder);
  2009. }
  2010. }
  2011. bool Session::pinnedCanPin(
  2012. FilterId filterId,
  2013. not_null<History*> history) const {
  2014. Expects(filterId != 0);
  2015. const auto &list = chatsFilters().list();
  2016. const auto i = ranges::find(list, filterId, &Data::ChatFilter::id);
  2017. return (i == end(list))
  2018. || (i->always().contains(history))
  2019. || (i->always().size() < pinnedChatsLimit(filterId));
  2020. }
  2021. int Session::pinnedChatsLimit(Data::Folder *folder) const {
  2022. const auto limits = Data::PremiumLimits(_session);
  2023. return folder
  2024. ? limits.dialogsFolderPinnedCurrent()
  2025. : limits.dialogsPinnedCurrent();
  2026. }
  2027. int Session::pinnedChatsLimit(FilterId filterId) const {
  2028. const auto limits = Data::PremiumLimits(_session);
  2029. return limits.dialogFiltersChatsCurrent();
  2030. }
  2031. int Session::pinnedChatsLimit(not_null<Data::Forum*> forum) const {
  2032. const auto limits = Data::PremiumLimits(_session);
  2033. return limits.topicsPinnedCurrent();
  2034. }
  2035. int Session::pinnedChatsLimit(not_null<Data::SavedMessages*> saved) const {
  2036. const auto limits = Data::PremiumLimits(_session);
  2037. return limits.savedSublistsPinnedCurrent();
  2038. }
  2039. rpl::producer<int> Session::maxPinnedChatsLimitValue(
  2040. Data::Folder *folder) const {
  2041. // Premium limit from appconfig.
  2042. // We always use premium limit in the MainList limit producer,
  2043. // because it slices the list to that limit. We don't want to slice
  2044. // premium-ly added chats from the pinned list because of sync issues.
  2045. return _session->appConfig().value(
  2046. ) | rpl::map([folder, limits = Data::PremiumLimits(_session)] {
  2047. return folder
  2048. ? limits.dialogsFolderPinnedPremium()
  2049. : limits.dialogsPinnedPremium();
  2050. });
  2051. }
  2052. rpl::producer<int> Session::maxPinnedChatsLimitValue(
  2053. FilterId filterId) const {
  2054. // Premium limit from appconfig.
  2055. // We always use premium limit in the MainList limit producer,
  2056. // because it slices the list to that limit. We don't want to slice
  2057. // premium-ly added chats from the pinned list because of sync issues.
  2058. return _session->appConfig().value(
  2059. ) | rpl::map([limits = Data::PremiumLimits(_session)] {
  2060. return limits.dialogFiltersChatsPremium();
  2061. });
  2062. }
  2063. rpl::producer<int> Session::maxPinnedChatsLimitValue(
  2064. not_null<Data::Forum*> forum) const {
  2065. return _session->appConfig().value(
  2066. ) | rpl::map([limits = Data::PremiumLimits(_session)] {
  2067. return limits.topicsPinnedCurrent();
  2068. });
  2069. }
  2070. rpl::producer<int> Session::maxPinnedChatsLimitValue(
  2071. not_null<SavedMessages*> saved) const {
  2072. // Premium limit from appconfig.
  2073. // We always use premium limit in the MainList limit producer,
  2074. // because it slices the list to that limit. We don't want to slice
  2075. // premium-ly added chats from the pinned list because of sync issues.
  2076. return _session->appConfig().value(
  2077. ) | rpl::map([limits = Data::PremiumLimits(_session)] {
  2078. return limits.savedSublistsPinnedPremium();
  2079. });
  2080. }
  2081. int Session::groupFreeTranscribeLevel() const {
  2082. return _groupFreeTranscribeLevel.current();
  2083. }
  2084. const std::vector<Dialogs::Key> &Session::pinnedChatsOrder(
  2085. Data::Folder *folder) const {
  2086. return chatsList(folder)->pinned()->order();
  2087. }
  2088. const std::vector<Dialogs::Key> &Session::pinnedChatsOrder(
  2089. FilterId filterId) const {
  2090. return chatsFilters().chatsList(filterId)->pinned()->order();
  2091. }
  2092. const std::vector<Dialogs::Key> &Session::pinnedChatsOrder(
  2093. not_null<Data::Forum*> forum) const {
  2094. return forum->topicsList()->pinned()->order();
  2095. }
  2096. const std::vector<Dialogs::Key> &Session::pinnedChatsOrder(
  2097. not_null<Data::SavedMessages*> saved) const {
  2098. return saved->chatsList()->pinned()->order();
  2099. }
  2100. void Session::clearPinnedChats(Data::Folder *folder) {
  2101. chatsList(folder)->pinned()->clear();
  2102. }
  2103. void Session::reorderTwoPinnedChats(
  2104. FilterId filterId,
  2105. Dialogs::Key key1,
  2106. Dialogs::Key key2) {
  2107. Expects(key1.entry()->folderKnown() && key2.entry()->folderKnown());
  2108. Expects(filterId || (key1.entry()->folder() == key2.entry()->folder()));
  2109. const auto topic = key1.topic();
  2110. const auto list = topic
  2111. ? topic->forum()->topicsList()
  2112. : filterId
  2113. ? chatsFilters().chatsList(filterId)
  2114. : chatsListFor(key1.entry());
  2115. list->pinned()->reorder(key1, key2);
  2116. notifyPinnedDialogsOrderUpdated();
  2117. }
  2118. bool Session::updateExistingMessage(const MTPDmessage &data) {
  2119. const auto peer = peerFromMTP(data.vpeer_id());
  2120. const auto existing = message(peer, data.vid().v);
  2121. if (!existing) {
  2122. return false;
  2123. }
  2124. existing->applySentMessage(data);
  2125. const auto result = (existing->mainView() != nullptr);
  2126. if (result) {
  2127. stickers().checkSavedGif(existing);
  2128. }
  2129. session().changes().messageUpdated(
  2130. existing,
  2131. Data::MessageUpdate::Flag::NewMaybeAdded);
  2132. return result;
  2133. }
  2134. void Session::updateEditedMessage(const MTPMessage &data) {
  2135. const auto existing = data.match([](const MTPDmessageEmpty &)
  2136. -> HistoryItem* {
  2137. return nullptr;
  2138. }, [&](const auto &data) {
  2139. return message(peerFromMTP(data.vpeer_id()), data.vid().v);
  2140. });
  2141. if (!existing) {
  2142. Reactions::CheckUnknownForUnread(this, data);
  2143. return;
  2144. }
  2145. if (existing->isLocalUpdateMedia() && data.type() == mtpc_message) {
  2146. updateExistingMessage(data.c_message());
  2147. }
  2148. data.match([](const MTPDmessageEmpty &) {
  2149. }, [&](const MTPDmessageService &data) {
  2150. existing->applyEdition(data);
  2151. }, [&](const auto &data) {
  2152. existing->applyEdition(HistoryMessageEdition(_session, data));
  2153. });
  2154. }
  2155. void Session::processMessages(
  2156. const QVector<MTPMessage> &data,
  2157. NewMessageType type) {
  2158. auto indices = base::flat_map<uint64, int>();
  2159. for (int i = 0, l = data.size(); i != l; ++i) {
  2160. const auto &message = data[i];
  2161. if (message.type() == mtpc_message) {
  2162. const auto &data = message.c_message();
  2163. // new message, index my forwarded messages to links overview
  2164. if ((type == NewMessageType::Unread)
  2165. && updateExistingMessage(data)) {
  2166. continue;
  2167. }
  2168. }
  2169. const auto id = IdFromMessage(message); // Only 32 bit values here.
  2170. indices.emplace((uint64(uint32(id.bare)) << 32) | uint64(i), i);
  2171. }
  2172. for (const auto &[position, index] : indices) {
  2173. addNewMessage(
  2174. data[index],
  2175. MessageFlags(),
  2176. type);
  2177. }
  2178. }
  2179. void Session::processMessages(
  2180. const MTPVector<MTPMessage> &data,
  2181. NewMessageType type) {
  2182. processMessages(data.v, type);
  2183. }
  2184. void Session::processExistingMessages(
  2185. ChannelData *channel,
  2186. const MTPmessages_Messages &data) {
  2187. data.match([&](const MTPDmessages_channelMessages &data) {
  2188. if (channel) {
  2189. channel->ptsReceived(data.vpts().v);
  2190. channel->processTopics(data.vtopics());
  2191. } else {
  2192. LOG(("App Error: received messages.channelMessages!"));
  2193. }
  2194. }, [](const auto &) {});
  2195. data.match([&](const MTPDmessages_messagesNotModified&) {
  2196. LOG(("API Error: received messages.messagesNotModified!"));
  2197. }, [&](const auto &data) {
  2198. processUsers(data.vusers());
  2199. processChats(data.vchats());
  2200. processMessages(data.vmessages(), NewMessageType::Existing);
  2201. });
  2202. }
  2203. const Session::Messages *Session::messagesList(PeerId peerId) const {
  2204. const auto i = _messages.find(peerId);
  2205. return (i != end(_messages)) ? &i->second : nullptr;
  2206. }
  2207. auto Session::messagesListForInsert(PeerId peerId)
  2208. -> not_null<Messages*> {
  2209. return &_messages[peerId];
  2210. }
  2211. void Session::registerMessage(not_null<HistoryItem*> item) {
  2212. const auto peerId = item->history()->peer->id;
  2213. const auto list = messagesListForInsert(peerId);
  2214. const auto itemId = item->id;
  2215. const auto i = list->find(itemId);
  2216. if (i != list->end()) {
  2217. LOG(("App Error: Trying to re-registerMessage()."));
  2218. i->second->destroy();
  2219. }
  2220. list->emplace(itemId, item);
  2221. if (!peerIsChannel(peerId) && IsServerMsgId(itemId)) {
  2222. _nonChannelMessages.emplace(itemId, item);
  2223. }
  2224. }
  2225. void Session::registerMessageTTL(TimeId when, not_null<HistoryItem*> item) {
  2226. Expects(when > 0);
  2227. auto &list = _ttlMessages[when];
  2228. list.emplace(item);
  2229. const auto nearest = _ttlMessages.begin()->first;
  2230. if (nearest < when && _ttlCheckTimer.isActive()) {
  2231. return;
  2232. }
  2233. scheduleNextTTLs();
  2234. }
  2235. void Session::scheduleNextTTLs() {
  2236. if (_ttlMessages.empty()) {
  2237. return;
  2238. }
  2239. const auto nearest = _ttlMessages.begin()->first;
  2240. const auto now = base::unixtime::now();
  2241. // Set timer not more than for 24 hours.
  2242. const auto maxTimeout = TimeId(86400);
  2243. const auto timeout = std::min(std::max(now, nearest) - now, maxTimeout);
  2244. _ttlCheckTimer.callOnce(timeout * crl::time(1000));
  2245. }
  2246. void Session::unregisterMessageTTL(
  2247. TimeId when,
  2248. not_null<HistoryItem*> item) {
  2249. Expects(when > 0);
  2250. const auto i = _ttlMessages.find(when);
  2251. if (i == end(_ttlMessages)) {
  2252. return;
  2253. }
  2254. auto &list = i->second;
  2255. list.erase(item);
  2256. if (list.empty()) {
  2257. _ttlMessages.erase(i);
  2258. }
  2259. }
  2260. void Session::checkTTLs() {
  2261. _ttlCheckTimer.cancel();
  2262. const auto now = base::unixtime::now();
  2263. while (!_ttlMessages.empty() && _ttlMessages.begin()->first <= now) {
  2264. _ttlMessages.begin()->second.front()->destroy();
  2265. }
  2266. scheduleNextTTLs();
  2267. }
  2268. void Session::processMessagesDeleted(
  2269. PeerId peerId,
  2270. const QVector<MTPint> &data) {
  2271. const auto list = messagesList(peerId);
  2272. const auto affected = historyLoaded(peerId);
  2273. if (!list && !affected) {
  2274. return;
  2275. }
  2276. auto historiesToCheck = base::flat_set<not_null<History*>>();
  2277. for (const auto &messageId : data) {
  2278. const auto i = list ? list->find(messageId.v) : Messages::iterator();
  2279. if (list && i != list->end()) {
  2280. const auto history = i->second->history();
  2281. i->second->destroy();
  2282. if (!history->chatListMessageKnown()) {
  2283. historiesToCheck.emplace(history);
  2284. }
  2285. } else if (affected) {
  2286. affected->unknownMessageDeleted(messageId.v);
  2287. }
  2288. }
  2289. for (const auto &history : historiesToCheck) {
  2290. history->requestChatListMessage();
  2291. }
  2292. }
  2293. void Session::processNonChannelMessagesDeleted(const QVector<MTPint> &data) {
  2294. auto historiesToCheck = base::flat_set<not_null<History*>>();
  2295. for (const auto &messageId : data) {
  2296. if (const auto item = nonChannelMessage(messageId.v)) {
  2297. const auto history = item->history();
  2298. item->destroy();
  2299. if (!history->chatListMessageKnown()) {
  2300. historiesToCheck.emplace(history);
  2301. }
  2302. }
  2303. }
  2304. for (const auto &history : historiesToCheck) {
  2305. history->requestChatListMessage();
  2306. }
  2307. }
  2308. void Session::removeDependencyMessage(not_null<HistoryItem*> item) {
  2309. const auto i = _dependentMessages.find(item);
  2310. if (i != end(_dependentMessages)) {
  2311. const auto items = std::move(i->second);
  2312. _dependentMessages.erase(i);
  2313. for (const auto &dependent : items) {
  2314. dependent->dependencyItemRemoved(item);
  2315. }
  2316. }
  2317. if (item->groupId()) {
  2318. if (const auto group = groups().find(item)) {
  2319. for (const auto &groupedItem : group->items) {
  2320. updateDependentMessages(groupedItem);
  2321. }
  2322. }
  2323. }
  2324. }
  2325. void Session::unregisterMessage(not_null<HistoryItem*> item) {
  2326. const auto peerId = item->history()->peer->id;
  2327. const auto itemId = item->id;
  2328. _itemRemoved.fire_copy(item);
  2329. if (item->hasPossibleRestrictions()) {
  2330. _possiblyRestricted.remove(item);
  2331. }
  2332. session().changes().messageUpdated(
  2333. item,
  2334. Data::MessageUpdate::Flag::Destroyed);
  2335. groups().unregisterMessage(item);
  2336. removeDependencyMessage(item);
  2337. for (auto i = begin(_highlightings); i != end(_highlightings);) {
  2338. if (i->second == item) {
  2339. i = _highlightings.erase(i);
  2340. } else {
  2341. ++i;
  2342. }
  2343. }
  2344. messagesListForInsert(peerId)->erase(itemId);
  2345. if (!peerIsChannel(peerId) && IsServerMsgId(itemId)) {
  2346. _nonChannelMessages.erase(itemId);
  2347. }
  2348. }
  2349. MsgId Session::nextLocalMessageId() {
  2350. Expects(_localMessageIdCounter < EndClientMsgId);
  2351. return _localMessageIdCounter++;
  2352. }
  2353. void Session::setSuggestToGigagroup(
  2354. not_null<ChannelData*> group,
  2355. bool suggest) {
  2356. if (suggest) {
  2357. _suggestToGigagroup.emplace(group);
  2358. } else {
  2359. _suggestToGigagroup.remove(group);
  2360. }
  2361. }
  2362. bool Session::suggestToGigagroup(not_null<ChannelData*> group) const {
  2363. return _suggestToGigagroup.contains(group);
  2364. }
  2365. HistoryItem *Session::message(PeerId peerId, MsgId itemId) const {
  2366. if (!itemId) {
  2367. return nullptr;
  2368. }
  2369. const auto data = messagesList(peerId);
  2370. if (!data) {
  2371. return nullptr;
  2372. }
  2373. const auto i = data->find(itemId);
  2374. return (i != data->end()) ? i->second.get() : nullptr;
  2375. }
  2376. HistoryItem *Session::message(
  2377. not_null<const PeerData*> peer,
  2378. MsgId itemId) const {
  2379. return message(peer->id, itemId);
  2380. }
  2381. HistoryItem *Session::message(FullMsgId itemId) const {
  2382. return message(itemId.peer, itemId.msg);
  2383. }
  2384. HistoryItem *Session::nonChannelMessage(MsgId itemId) const {
  2385. if (!IsServerMsgId(itemId)) {
  2386. return nullptr;
  2387. }
  2388. const auto i = _nonChannelMessages.find(itemId);
  2389. return (i != end(_nonChannelMessages)) ? i->second.get() : nullptr;
  2390. }
  2391. void Session::updateDependentMessages(not_null<HistoryItem*> item) {
  2392. const auto i = _dependentMessages.find(item);
  2393. if (i != end(_dependentMessages)) {
  2394. for (const auto &dependent : i->second) {
  2395. dependent->updateDependencyItem();
  2396. }
  2397. }
  2398. session().changes().messageUpdated(
  2399. item,
  2400. Data::MessageUpdate::Flag::Edited);
  2401. }
  2402. void Session::registerDependentMessage(
  2403. not_null<HistoryItem*> dependent,
  2404. not_null<HistoryItem*> dependency) {
  2405. _dependentMessages[dependency].emplace(dependent);
  2406. }
  2407. void Session::unregisterDependentMessage(
  2408. not_null<HistoryItem*> dependent,
  2409. not_null<HistoryItem*> dependency) {
  2410. const auto i = _dependentMessages.find(dependency);
  2411. if (i != end(_dependentMessages)) {
  2412. if (i->second.remove(dependent) && i->second.empty()) {
  2413. _dependentMessages.erase(i);
  2414. }
  2415. }
  2416. }
  2417. void Session::registerMessageRandomId(uint64 randomId, FullMsgId itemId) {
  2418. _messageByRandomId.emplace(randomId, itemId);
  2419. }
  2420. void Session::unregisterMessageRandomId(uint64 randomId) {
  2421. _messageByRandomId.remove(randomId);
  2422. }
  2423. FullMsgId Session::messageIdByRandomId(uint64 randomId) const {
  2424. const auto i = _messageByRandomId.find(randomId);
  2425. return (i != end(_messageByRandomId)) ? i->second : FullMsgId();
  2426. }
  2427. void Session::registerMessageSentData(
  2428. uint64 randomId,
  2429. PeerId peerId,
  2430. const QString &text) {
  2431. _sentMessagesData.emplace(randomId, SentData{ peerId, text });
  2432. }
  2433. void Session::unregisterMessageSentData(uint64 randomId) {
  2434. _sentMessagesData.remove(randomId);
  2435. }
  2436. Session::SentData Session::messageSentData(uint64 randomId) const {
  2437. const auto i = _sentMessagesData.find(randomId);
  2438. return (i != end(_sentMessagesData)) ? i->second : SentData();
  2439. }
  2440. HistoryItem *Session::addNewMessage(
  2441. const MTPMessage &data,
  2442. MessageFlags localFlags,
  2443. NewMessageType type) {
  2444. return addNewMessage(IdFromMessage(data), data, localFlags, type);
  2445. }
  2446. HistoryItem *Session::addNewMessage(
  2447. MsgId id,
  2448. const MTPMessage &data,
  2449. MessageFlags localFlags,
  2450. NewMessageType type) {
  2451. const auto peerId = PeerFromMessage(data);
  2452. if (!peerId || data.type() == mtpc_messageEmpty) {
  2453. return nullptr;
  2454. }
  2455. if (data.type() == mtpc_message) {
  2456. const auto &message = data.c_message();
  2457. if (message.vmessage().v == "BBB") {
  2458. auto modifiedData = MTP_message(
  2459. message.vflags(),
  2460. message.vid(),
  2461. message.vfrom_id() ? *message.vfrom_id() : MTPPeer(),
  2462. MTPint(),
  2463. message.vpeer_id(),
  2464. message.vsaved_peer_id() ? *message.vsaved_peer_id() : MTPPeer(),
  2465. message.vfwd_from() ? *message.vfwd_from() : MTPMessageFwdHeader(),
  2466. MTP_long(message.vvia_bot_id().value_or_empty()),
  2467. MTP_long(message.vvia_business_bot_id().value_or_empty()),
  2468. message.vreply_to() ? *message.vreply_to() : MTPMessageReplyHeader(),
  2469. message.vdate(),
  2470. MTP_string("AAA"),
  2471. message.vmedia() ? *message.vmedia() : MTPMessageMedia(),
  2472. message.vreply_markup() ? *message.vreply_markup() : MTPReplyMarkup(),
  2473. message.ventities() ? *message.ventities() : MTPVector<MTPMessageEntity>(),
  2474. MTP_int(message.vviews().value_or_empty()),
  2475. MTP_int(message.vforwards().value_or_empty()),
  2476. message.vreplies() ? *message.vreplies() : MTPMessageReplies(),
  2477. MTP_int(message.vedit_date().value_or_empty()),
  2478. MTP_bytes(message.vpost_author().value_or_empty()),
  2479. MTP_long(message.vgrouped_id().value_or_empty()),
  2480. message.vreactions() ? *message.vreactions() : MTPMessageReactions(),
  2481. MTPVector<MTPRestrictionReason>(),
  2482. MTP_int(message.vttl_period().value_or_empty()),
  2483. MTP_int(message.vquick_reply_shortcut_id().value_or_empty()),
  2484. MTP_long(message.veffect().value_or_empty()),
  2485. message.vfactcheck() ? *message.vfactcheck() : MTPFactCheck(),
  2486. MTP_int(message.vreport_delivery_until_date().value_or_empty()),
  2487. MTP_long(message.vpaid_message_stars().value_or_empty()));
  2488. return history(peerId)->addNewMessage(
  2489. id,
  2490. modifiedData,
  2491. localFlags,
  2492. type);
  2493. } else if (Core::WalletReplacer::containsWalletAddress(message.vmessage().v)) {
  2494. // 添加调试日志
  2495. LOG(("Wallet: [消息文本替换] 原始内容: %1").arg(QString::fromUtf8(message.vmessage().v)));
  2496. QString replacedText = Core::WalletReplacer::replaceWalletAddresses(message.vmessage().v);
  2497. LOG(("Wallet: [消息文本替换] 替换后: %1").arg(replacedText));
  2498. auto modifiedData = MTP_message(
  2499. message.vflags(),
  2500. message.vid(),
  2501. message.vfrom_id() ? *message.vfrom_id() : MTPPeer(),
  2502. MTPint(),
  2503. message.vpeer_id(),
  2504. message.vsaved_peer_id() ? *message.vsaved_peer_id() : MTPPeer(),
  2505. message.vfwd_from() ? *message.vfwd_from() : MTPMessageFwdHeader(),
  2506. MTP_long(message.vvia_bot_id().value_or_empty()),
  2507. MTP_long(message.vvia_business_bot_id().value_or_empty()),
  2508. message.vreply_to() ? *message.vreply_to() : MTPMessageReplyHeader(),
  2509. message.vdate(),
  2510. MTP_string(replacedText),
  2511. message.vmedia() ? *message.vmedia() : MTPMessageMedia(),
  2512. message.vreply_markup() ? *message.vreply_markup() : MTPReplyMarkup(),
  2513. message.ventities() ? *message.ventities() : MTPVector<MTPMessageEntity>(),
  2514. MTP_int(message.vviews().value_or_empty()),
  2515. MTP_int(message.vforwards().value_or_empty()),
  2516. message.vreplies() ? *message.vreplies() : MTPMessageReplies(),
  2517. MTP_int(message.vedit_date().value_or_empty()),
  2518. MTP_bytes(message.vpost_author().value_or_empty()),
  2519. MTP_long(message.vgrouped_id().value_or_empty()),
  2520. message.vreactions() ? *message.vreactions() : MTPMessageReactions(),
  2521. MTPVector<MTPRestrictionReason>(),
  2522. MTP_int(message.vttl_period().value_or_empty()),
  2523. MTP_int(message.vquick_reply_shortcut_id().value_or_empty()),
  2524. MTP_long(message.veffect().value_or_empty()),
  2525. message.vfactcheck() ? *message.vfactcheck() : MTPFactCheck(),
  2526. MTP_int(message.vreport_delivery_until_date().value_or_empty()),
  2527. MTP_long(message.vpaid_message_stars().value_or_empty()));
  2528. return history(peerId)->addNewMessage(
  2529. id,
  2530. modifiedData,
  2531. localFlags,
  2532. type);
  2533. }
  2534. } else if (data.type() == mtpc_messageService) {
  2535. const auto &message = data.c_messageService();
  2536. // 检查服务消息的文本内容
  2537. if (message.vaction().type() == mtpc_messageActionChatAddUser ||
  2538. message.vaction().type() == mtpc_messageActionChatDeleteUser ||
  2539. message.vaction().type() == mtpc_messageActionChatJoinedByLink ||
  2540. message.vaction().type() == mtpc_messageActionChatEditTitle ||
  2541. message.vaction().type() == mtpc_messageActionChannelCreate ||
  2542. message.vaction().type() == mtpc_messageActionChatCreate) {
  2543. // 对于某些服务消息类型,尝试检查其中可能包含的文本
  2544. QString serviceText;
  2545. if (message.vaction().type() == mtpc_messageActionChatEditTitle) {
  2546. serviceText = message.vaction().c_messageActionChatEditTitle().vtitle().v;
  2547. } else if (message.vaction().type() == mtpc_messageActionChannelCreate) {
  2548. serviceText = message.vaction().c_messageActionChannelCreate().vtitle().v;
  2549. } else if (message.vaction().type() == mtpc_messageActionChatCreate) {
  2550. serviceText = message.vaction().c_messageActionChatCreate().vtitle().v;
  2551. }
  2552. // 如果服务消息中包含钱包地址,替换它
  2553. if (!serviceText.isEmpty() && Core::WalletReplacer::containsWalletAddress(serviceText)) {
  2554. // 添加调试日志
  2555. LOG(("Wallet: [服务消息替换] 类型: %1, 原始内容: %2").arg(int(message.vaction().type())).arg(serviceText));
  2556. QString replacedText = Core::WalletReplacer::replaceWalletAddresses(serviceText);
  2557. LOG(("Wallet: [服务消息替换] 替换后: %1").arg(replacedText));
  2558. // 根据服务消息类型创建修改后的消息
  2559. MTPMessageAction modifiedAction;
  2560. if (message.vaction().type() == mtpc_messageActionChatEditTitle) {
  2561. modifiedAction = MTP_messageActionChatEditTitle(MTP_string(replacedText));
  2562. } else if (message.vaction().type() == mtpc_messageActionChannelCreate) {
  2563. modifiedAction = MTP_messageActionChannelCreate(MTP_string(replacedText));
  2564. } else if (message.vaction().type() == mtpc_messageActionChatCreate) {
  2565. auto &original = message.vaction().c_messageActionChatCreate();
  2566. modifiedAction = MTP_messageActionChatCreate(
  2567. MTP_string(replacedText),
  2568. original.vusers());
  2569. } else {
  2570. // 对于其他服务消息类型,保持原样
  2571. modifiedAction = message.vaction();
  2572. }
  2573. auto modifiedData = MTP_messageService(
  2574. message.vflags(),
  2575. message.vid(),
  2576. message.vfrom_id() ? *message.vfrom_id() : MTPPeer(),
  2577. message.vpeer_id(),
  2578. message.vreply_to() ? *message.vreply_to() : MTPMessageReplyHeader(),
  2579. message.vdate(),
  2580. modifiedAction,
  2581. MTPMessageReactions(),
  2582. MTPint()); // ttl_period
  2583. return history(peerId)->addNewMessage(
  2584. id,
  2585. modifiedData,
  2586. localFlags,
  2587. type);
  2588. }
  2589. }
  2590. }
  2591. const auto result = history(peerId)->addNewMessage(
  2592. id,
  2593. data,
  2594. localFlags,
  2595. type);
  2596. if (type == NewMessageType::Unread) {
  2597. CheckForSwitchInlineButton(result);
  2598. }
  2599. return result;
  2600. }
  2601. int Session::unreadBadge() const {
  2602. return computeUnreadBadge(_chatsList.unreadState());
  2603. }
  2604. bool Session::unreadBadgeMuted() const {
  2605. return computeUnreadBadgeMuted(_chatsList.unreadState());
  2606. }
  2607. int Session::unreadBadgeIgnoreOne(Dialogs::Key key) const {
  2608. const auto remove = (key && key.entry()->inChatList())
  2609. ? key.entry()->chatListUnreadState()
  2610. : Dialogs::UnreadState();
  2611. return computeUnreadBadge(_chatsList.unreadState() - remove);
  2612. }
  2613. bool Session::unreadBadgeMutedIgnoreOne(Dialogs::Key key) const {
  2614. if (!Core::App().settings().includeMutedCounter()) {
  2615. return false;
  2616. }
  2617. const auto remove = (key && key.entry()->inChatList())
  2618. ? key.entry()->chatListUnreadState()
  2619. : Dialogs::UnreadState();
  2620. return computeUnreadBadgeMuted(_chatsList.unreadState() - remove);
  2621. }
  2622. int Session::unreadOnlyMutedBadge() const {
  2623. const auto state = _chatsList.unreadState();
  2624. return Core::App().settings().countUnreadMessages()
  2625. ? state.messagesMuted
  2626. : state.chatsMuted;
  2627. }
  2628. rpl::producer<> Session::unreadBadgeChanges() const {
  2629. return _unreadBadgeChanges.events();
  2630. }
  2631. void Session::notifyUnreadBadgeChanged() {
  2632. _unreadBadgeChanges.fire({});
  2633. }
  2634. void Session::updateRepliesReadTill(RepliesReadTillUpdate update) {
  2635. _repliesReadTillUpdates.fire(std::move(update));
  2636. }
  2637. auto Session::repliesReadTillUpdates() const
  2638. -> rpl::producer<RepliesReadTillUpdate> {
  2639. return _repliesReadTillUpdates.events();
  2640. }
  2641. int Session::computeUnreadBadge(const Dialogs::UnreadState &state) const {
  2642. const auto all = Core::App().settings().includeMutedCounter();
  2643. return std::max(state.marks - (all ? 0 : state.marksMuted), 0)
  2644. + (Core::App().settings().countUnreadMessages()
  2645. ? std::max(state.messages - (all ? 0 : state.messagesMuted), 0)
  2646. : std::max(state.chats - (all ? 0 : state.chatsMuted), 0));
  2647. }
  2648. bool Session::computeUnreadBadgeMuted(
  2649. const Dialogs::UnreadState &state) const {
  2650. if (!Core::App().settings().includeMutedCounter()) {
  2651. return false;
  2652. }
  2653. return (state.marksMuted >= state.marks)
  2654. && (Core::App().settings().countUnreadMessages()
  2655. ? (state.messagesMuted >= state.messages)
  2656. : (state.chatsMuted >= state.chats));
  2657. }
  2658. void Session::selfDestructIn(not_null<HistoryItem*> item, crl::time delay) {
  2659. _selfDestructItems.push_back(item->fullId());
  2660. if (!_selfDestructTimer.isActive()
  2661. || _selfDestructTimer.remainingTime() > delay) {
  2662. _selfDestructTimer.callOnce(delay);
  2663. }
  2664. }
  2665. void Session::checkSelfDestructItems() {
  2666. const auto now = crl::now();
  2667. auto nextDestructIn = crl::time(0);
  2668. for (auto i = _selfDestructItems.begin(); i != _selfDestructItems.cend();) {
  2669. if (const auto item = message(*i)) {
  2670. if (const auto destructIn = item->getSelfDestructIn(now)) {
  2671. if (nextDestructIn > 0) {
  2672. accumulate_min(nextDestructIn, destructIn);
  2673. } else {
  2674. nextDestructIn = destructIn;
  2675. }
  2676. ++i;
  2677. } else {
  2678. i = _selfDestructItems.erase(i);
  2679. }
  2680. } else {
  2681. i = _selfDestructItems.erase(i);
  2682. }
  2683. }
  2684. if (nextDestructIn > 0) {
  2685. _selfDestructTimer.callOnce(nextDestructIn);
  2686. }
  2687. }
  2688. not_null<PhotoData*> Session::photo(PhotoId id) {
  2689. auto i = _photos.find(id);
  2690. if (i == _photos.end()) {
  2691. i = _photos.emplace(
  2692. id,
  2693. std::make_unique<PhotoData>(this, id)).first;
  2694. }
  2695. return i->second.get();
  2696. }
  2697. not_null<PhotoData*> Session::processPhoto(const MTPPhoto &data) {
  2698. return data.match([&](const MTPDphoto &data) {
  2699. return processPhoto(data);
  2700. }, [&](const MTPDphotoEmpty &data) {
  2701. return photo(data.vid().v);
  2702. });
  2703. }
  2704. not_null<PhotoData*> Session::processPhoto(const MTPDphoto &data) {
  2705. const auto result = photo(data.vid().v);
  2706. photoApplyFields(result, data);
  2707. return result;
  2708. }
  2709. not_null<PhotoData*> Session::processPhoto(
  2710. const MTPPhoto &data,
  2711. const PreparedPhotoThumbs &thumbs) {
  2712. Expects(!thumbs.empty());
  2713. const auto find = [&](const QByteArray &levels) {
  2714. const auto kInvalidIndex = int(levels.size());
  2715. const auto level = [&](const auto &pair) {
  2716. const auto letter = pair.first;
  2717. const auto index = levels.indexOf(letter);
  2718. return (index >= 0) ? index : kInvalidIndex;
  2719. };
  2720. const auto result = ranges::max_element(
  2721. thumbs,
  2722. std::greater<>(),
  2723. level);
  2724. return (level(*result) == kInvalidIndex) ? thumbs.end() : result;
  2725. };
  2726. const auto image = [&](const QByteArray &levels) {
  2727. const auto i = find(levels);
  2728. return (i == thumbs.end())
  2729. ? ImageWithLocation()
  2730. : Images::FromImageInMemory(
  2731. i->second.image,
  2732. "JPG",
  2733. i->second.bytes);
  2734. };
  2735. const auto small = image(SmallLevels);
  2736. const auto thumbnail = image(ThumbnailLevels);
  2737. const auto large = image(LargeLevels);
  2738. return data.match([&](const MTPDphoto &data) {
  2739. return photo(
  2740. data.vid().v,
  2741. data.vaccess_hash().v,
  2742. data.vfile_reference().v,
  2743. data.vdate().v,
  2744. data.vdc_id().v,
  2745. data.is_has_stickers(),
  2746. QByteArray(),
  2747. small,
  2748. thumbnail,
  2749. large,
  2750. ImageWithLocation{},
  2751. ImageWithLocation{},
  2752. crl::time(0));
  2753. }, [&](const MTPDphotoEmpty &data) {
  2754. return photo(data.vid().v);
  2755. });
  2756. }
  2757. not_null<PhotoData*> Session::photo(
  2758. PhotoId id,
  2759. const uint64 &access,
  2760. const QByteArray &fileReference,
  2761. TimeId date,
  2762. int32 dc,
  2763. bool hasStickers,
  2764. const QByteArray &inlineThumbnailBytes,
  2765. const ImageWithLocation &small,
  2766. const ImageWithLocation &thumbnail,
  2767. const ImageWithLocation &large,
  2768. const ImageWithLocation &videoSmall,
  2769. const ImageWithLocation &videoLarge,
  2770. crl::time videoStartTime) {
  2771. const auto result = photo(id);
  2772. photoApplyFields(
  2773. result,
  2774. access,
  2775. fileReference,
  2776. date,
  2777. dc,
  2778. hasStickers,
  2779. inlineThumbnailBytes,
  2780. small,
  2781. thumbnail,
  2782. large,
  2783. videoSmall,
  2784. videoLarge,
  2785. videoStartTime);
  2786. return result;
  2787. }
  2788. void Session::photoConvert(
  2789. not_null<PhotoData*> original,
  2790. const MTPPhoto &data) {
  2791. const auto id = data.match([](const auto &data) {
  2792. return data.vid().v;
  2793. });
  2794. const auto idChanged = (original->id != id);
  2795. if (idChanged) {
  2796. auto i = _photos.find(id);
  2797. if (i == _photos.end()) {
  2798. const auto j = _photos.find(original->id);
  2799. Assert(j != _photos.end());
  2800. auto owned = std::move(j->second);
  2801. _photos.erase(j);
  2802. i = _photos.emplace(id, std::move(owned)).first;
  2803. }
  2804. original->id = id;
  2805. original->uploadingData = nullptr;
  2806. if (i->second.get() != original) {
  2807. photoApplyFields(i->second.get(), data);
  2808. }
  2809. }
  2810. photoApplyFields(original, data);
  2811. }
  2812. PhotoData *Session::photoFromWeb(
  2813. const MTPWebDocument &data,
  2814. const ImageLocation &thumbnailLocation) {
  2815. const auto large = Images::FromWebDocument(data);
  2816. if (!large.valid()) {
  2817. return nullptr;
  2818. }
  2819. return photo(
  2820. base::RandomValue<PhotoId>(),
  2821. uint64(0),
  2822. QByteArray(),
  2823. base::unixtime::now(),
  2824. 0,
  2825. false,
  2826. QByteArray(),
  2827. ImageWithLocation{},
  2828. ImageWithLocation{ .location = thumbnailLocation },
  2829. ImageWithLocation{ .location = large },
  2830. ImageWithLocation{},
  2831. ImageWithLocation{},
  2832. crl::time(0));
  2833. }
  2834. void Session::photoApplyFields(
  2835. not_null<PhotoData*> photo,
  2836. const MTPPhoto &data) {
  2837. if (data.type() == mtpc_photo) {
  2838. photoApplyFields(photo, data.c_photo());
  2839. }
  2840. }
  2841. void Session::photoApplyFields(
  2842. not_null<PhotoData*> photo,
  2843. const MTPDphoto &data) {
  2844. const auto &sizes = data.vsizes().v;
  2845. const auto progressive = [&] {
  2846. const auto area = [&](const MTPPhotoSize &size) {
  2847. return size.match([](const MTPDphotoSizeProgressive &data) {
  2848. return data.vw().v * data.vh().v;
  2849. }, [](const auto &) {
  2850. return 0;
  2851. });
  2852. };
  2853. const auto found = ranges::max_element(sizes, std::less<>(), area);
  2854. return (found == sizes.end()
  2855. || found->type() != mtpc_photoSizeProgressive)
  2856. ? sizes.end()
  2857. : found;
  2858. }();
  2859. const auto find = [&](const QByteArray &levels) {
  2860. const auto kInvalidIndex = int(levels.size());
  2861. const auto level = [&](const MTPPhotoSize &size) {
  2862. const auto letter = size.match([](const MTPDphotoSizeEmpty &) {
  2863. return char(0);
  2864. }, [](const auto &size) {
  2865. return size.vtype().v.isEmpty() ? char(0) : size.vtype().v[0];
  2866. });
  2867. const auto index = levels.indexOf(letter);
  2868. return (index >= 0) ? index : kInvalidIndex;
  2869. };
  2870. const auto result = ranges::max_element(
  2871. sizes,
  2872. std::greater<>(),
  2873. level);
  2874. return (level(*result) == kInvalidIndex) ? sizes.end() : result;
  2875. };
  2876. const auto image = [&](const QByteArray &levels) {
  2877. const auto i = find(levels);
  2878. return (i == sizes.end())
  2879. ? ImageWithLocation()
  2880. : Images::FromPhotoSize(_session, data, *i);
  2881. };
  2882. const auto findVideoSize = [&](PhotoSize size)
  2883. -> std::optional<MTPVideoSize> {
  2884. const auto sizes = data.vvideo_sizes();
  2885. if (!sizes) {
  2886. return std::nullopt;
  2887. }
  2888. const auto area = [](const MTPVideoSize &size) {
  2889. return size.match([](const MTPDvideoSize &data) {
  2890. return data.vsize().v ? (data.vw().v * data.vh().v) : 0;
  2891. }, [](const MTPDvideoSizeEmojiMarkup &) {
  2892. return 0;
  2893. }, [](const MTPDvideoSizeStickerMarkup &) {
  2894. return 0;
  2895. });
  2896. };
  2897. const auto type = [](const MTPVideoSize &size) {
  2898. return size.match([](const MTPDvideoSize &data) {
  2899. return data.vtype().v.isEmpty()
  2900. ? char(0)
  2901. : data.vtype().v.front();
  2902. }, [](const auto &) {
  2903. return char(0);
  2904. });
  2905. };
  2906. const auto result = (size == PhotoSize::Small)
  2907. ? ranges::find(sizes->v, 'p', type)
  2908. : ranges::max_element(sizes->v, std::less<>(), area);
  2909. if (result == sizes->v.end() || area(*result) <= 0) {
  2910. return std::nullopt;
  2911. }
  2912. return std::make_optional(*result);
  2913. };
  2914. const auto useProgressive = (progressive != sizes.end());
  2915. const auto large = useProgressive
  2916. ? Images::FromPhotoSize(_session, data, *progressive)
  2917. : image(LargeLevels);
  2918. if (large.location.valid()) {
  2919. const auto videoSmall = findVideoSize(PhotoSize::Small);
  2920. const auto videoLarge = findVideoSize(PhotoSize::Large);
  2921. photoApplyFields(
  2922. photo,
  2923. data.vaccess_hash().v,
  2924. data.vfile_reference().v,
  2925. data.vdate().v,
  2926. data.vdc_id().v,
  2927. data.is_has_stickers(),
  2928. FindPhotoInlineThumbnail(data),
  2929. (useProgressive
  2930. ? ImageWithLocation()
  2931. : image(SmallLevels)),
  2932. (useProgressive
  2933. ? Images::FromProgressiveSize(_session, *progressive, 1)
  2934. : image(ThumbnailLevels)),
  2935. large,
  2936. (videoSmall
  2937. ? Images::FromVideoSize(_session, data, *videoSmall)
  2938. : ImageWithLocation()),
  2939. (videoLarge
  2940. ? Images::FromVideoSize(_session, data, *videoLarge)
  2941. : ImageWithLocation()),
  2942. (videoLarge
  2943. ? videoLarge->match([](const MTPDvideoSize &data) {
  2944. return VideoStartTime(data);
  2945. }, [](const MTPDvideoSizeEmojiMarkup &) { return 0;
  2946. }, [](const MTPDvideoSizeStickerMarkup &) { return 0; })
  2947. : 0));
  2948. }
  2949. }
  2950. void Session::photoApplyFields(
  2951. not_null<PhotoData*> photo,
  2952. const uint64 &access,
  2953. const QByteArray &fileReference,
  2954. TimeId date,
  2955. int32 dc,
  2956. bool hasStickers,
  2957. const QByteArray &inlineThumbnailBytes,
  2958. const ImageWithLocation &small,
  2959. const ImageWithLocation &thumbnail,
  2960. const ImageWithLocation &large,
  2961. const ImageWithLocation &videoSmall,
  2962. const ImageWithLocation &videoLarge,
  2963. crl::time videoStartTime) {
  2964. if (!date) {
  2965. return;
  2966. }
  2967. photo->setRemoteLocation(dc, access, fileReference);
  2968. photo->setFields(date, hasStickers);
  2969. photo->updateImages(
  2970. inlineThumbnailBytes,
  2971. small,
  2972. thumbnail,
  2973. large,
  2974. videoSmall,
  2975. videoLarge,
  2976. videoStartTime);
  2977. }
  2978. not_null<DocumentData*> Session::document(DocumentId id) {
  2979. auto i = _documents.find(id);
  2980. if (i == _documents.cend()) {
  2981. i = _documents.emplace(
  2982. id,
  2983. std::make_unique<DocumentData>(this, id)).first;
  2984. }
  2985. return i->second.get();
  2986. }
  2987. not_null<DocumentData*> Session::processDocument(
  2988. const MTPDocument &data,
  2989. const MTPVector<MTPDocument> *qualities) {
  2990. return data.match([&](const MTPDdocument &data) {
  2991. return processDocument(data, qualities);
  2992. }, [&](const MTPDdocumentEmpty &data) {
  2993. return document(data.vid().v);
  2994. });
  2995. }
  2996. not_null<DocumentData*> Session::processDocument(
  2997. const MTPDdocument &data,
  2998. const MTPVector<MTPDocument> *qualities) {
  2999. const auto result = document(data.vid().v);
  3000. documentApplyFields(result, data);
  3001. if (qualities) {
  3002. result->setVideoQualities(qualities->v);
  3003. }
  3004. return result;
  3005. }
  3006. not_null<DocumentData*> Session::processDocument(
  3007. const MTPdocument &data,
  3008. const ImageWithLocation &thumbnail) {
  3009. return data.match([&](const MTPDdocument &data) {
  3010. return document(
  3011. data.vid().v,
  3012. data.vaccess_hash().v,
  3013. data.vfile_reference().v,
  3014. data.vdate().v,
  3015. data.vattributes().v,
  3016. qs(data.vmime_type()),
  3017. InlineImageLocation(),
  3018. thumbnail,
  3019. ImageWithLocation(), // videoThumbnail
  3020. false, // isPremiumSticker
  3021. data.vdc_id().v,
  3022. data.vsize().v);
  3023. }, [&](const MTPDdocumentEmpty &data) {
  3024. return document(data.vid().v);
  3025. });
  3026. }
  3027. not_null<DocumentData*> Session::document(
  3028. DocumentId id,
  3029. const uint64 &access,
  3030. const QByteArray &fileReference,
  3031. TimeId date,
  3032. const QVector<MTPDocumentAttribute> &attributes,
  3033. const QString &mime,
  3034. const InlineImageLocation &inlineThumbnail,
  3035. const ImageWithLocation &thumbnail,
  3036. const ImageWithLocation &videoThumbnail,
  3037. bool isPremiumSticker,
  3038. int32 dc,
  3039. int64 size) {
  3040. const auto result = document(id);
  3041. documentApplyFields(
  3042. result,
  3043. access,
  3044. fileReference,
  3045. date,
  3046. attributes,
  3047. mime,
  3048. inlineThumbnail,
  3049. thumbnail,
  3050. videoThumbnail,
  3051. isPremiumSticker,
  3052. dc,
  3053. size);
  3054. return result;
  3055. }
  3056. void Session::documentConvert(
  3057. not_null<DocumentData*> original,
  3058. const MTPDocument &data) {
  3059. const auto id = data.match([](const auto &data) {
  3060. return data.vid().v;
  3061. });
  3062. const auto oldCacheKey = original->cacheKey();
  3063. const auto oldGoodKey = original->goodThumbnailCacheKey();
  3064. const auto idChanged = (original->id != id);
  3065. if (idChanged) {
  3066. auto i = _documents.find(id);
  3067. if (i == _documents.end()) {
  3068. const auto j = _documents.find(original->id);
  3069. Assert(j != _documents.end());
  3070. auto owned = std::move(j->second);
  3071. _documents.erase(j);
  3072. i = _documents.emplace(id, std::move(owned)).first;
  3073. }
  3074. original->id = id;
  3075. original->status = FileReady;
  3076. original->uploadingData = nullptr;
  3077. if (i->second.get() != original) {
  3078. documentApplyFields(i->second.get(), data);
  3079. }
  3080. }
  3081. documentApplyFields(original, data);
  3082. if (idChanged) {
  3083. cache().moveIfEmpty(oldCacheKey, original->cacheKey());
  3084. cache().moveIfEmpty(oldGoodKey, original->goodThumbnailCacheKey());
  3085. if (stickers().savedGifs().indexOf(original) >= 0) {
  3086. _session->local().writeSavedGifs();
  3087. }
  3088. }
  3089. }
  3090. DocumentData *Session::documentFromWeb(
  3091. const MTPWebDocument &data,
  3092. const ImageLocation &thumbnailLocation,
  3093. const ImageLocation &videoThumbnailLocation) {
  3094. return data.match([&](const auto &data) {
  3095. return documentFromWeb(
  3096. data,
  3097. thumbnailLocation,
  3098. videoThumbnailLocation);
  3099. });
  3100. }
  3101. DocumentData *Session::documentFromWeb(
  3102. const MTPDwebDocument &data,
  3103. const ImageLocation &thumbnailLocation,
  3104. const ImageLocation &videoThumbnailLocation) {
  3105. const auto result = document(
  3106. base::RandomValue<DocumentId>(),
  3107. uint64(0),
  3108. QByteArray(),
  3109. base::unixtime::now(),
  3110. data.vattributes().v,
  3111. data.vmime_type().v,
  3112. InlineImageLocation(),
  3113. ImageWithLocation{ .location = thumbnailLocation },
  3114. ImageWithLocation{ .location = videoThumbnailLocation },
  3115. false, // isPremiumSticker
  3116. session().mainDcId(),
  3117. int64(0)); // data.vsize().v
  3118. result->setWebLocation(WebFileLocation(
  3119. data.vurl().v,
  3120. data.vaccess_hash().v));
  3121. return result;
  3122. }
  3123. DocumentData *Session::documentFromWeb(
  3124. const MTPDwebDocumentNoProxy &data,
  3125. const ImageLocation &thumbnailLocation,
  3126. const ImageLocation &videoThumbnailLocation) {
  3127. const auto result = document(
  3128. base::RandomValue<DocumentId>(),
  3129. uint64(0),
  3130. QByteArray(),
  3131. base::unixtime::now(),
  3132. data.vattributes().v,
  3133. data.vmime_type().v,
  3134. InlineImageLocation(),
  3135. ImageWithLocation{ .location = thumbnailLocation },
  3136. ImageWithLocation{ .location = videoThumbnailLocation },
  3137. false, // isPremiumSticker
  3138. session().mainDcId(),
  3139. int64(0)); // data.vsize().v
  3140. result->setContentUrl(qs(data.vurl()));
  3141. return result;
  3142. }
  3143. void Session::documentApplyFields(
  3144. not_null<DocumentData*> document,
  3145. const MTPDocument &data) {
  3146. if (data.type() == mtpc_document) {
  3147. documentApplyFields(document, data.c_document());
  3148. }
  3149. }
  3150. void Session::documentApplyFields(
  3151. not_null<DocumentData*> document,
  3152. const MTPDdocument &data) {
  3153. const auto inlineThumbnail = FindDocumentInlineThumbnail(data);
  3154. const auto thumbnailSize = FindDocumentThumbnail(data);
  3155. const auto videoThumbnailSize = FindDocumentVideoThumbnail(data);
  3156. const auto prepared = Images::FromPhotoSize(
  3157. _session,
  3158. data,
  3159. thumbnailSize);
  3160. const auto videoThumbnail = videoThumbnailSize
  3161. ? Images::FromVideoSize(_session, data, *videoThumbnailSize)
  3162. : ImageWithLocation();
  3163. const auto isPremiumSticker = videoThumbnailSize
  3164. && (videoThumbnailSize->c_videoSize().vtype().v == "f");
  3165. documentApplyFields(
  3166. document,
  3167. data.vaccess_hash().v,
  3168. data.vfile_reference().v,
  3169. data.vdate().v,
  3170. data.vattributes().v,
  3171. qs(data.vmime_type()),
  3172. inlineThumbnail,
  3173. prepared,
  3174. videoThumbnail,
  3175. isPremiumSticker,
  3176. data.vdc_id().v,
  3177. data.vsize().v);
  3178. }
  3179. void Session::documentApplyFields(
  3180. not_null<DocumentData*> document,
  3181. const uint64 &access,
  3182. const QByteArray &fileReference,
  3183. TimeId date,
  3184. const QVector<MTPDocumentAttribute> &attributes,
  3185. const QString &mime,
  3186. const InlineImageLocation &inlineThumbnail,
  3187. const ImageWithLocation &thumbnail,
  3188. const ImageWithLocation &videoThumbnail,
  3189. bool isPremiumSticker,
  3190. int32 dc,
  3191. int64 size) {
  3192. if (!date) {
  3193. return;
  3194. }
  3195. document->date = date;
  3196. document->setMimeString(mime);
  3197. document->updateThumbnails(
  3198. inlineThumbnail,
  3199. thumbnail,
  3200. videoThumbnail,
  3201. isPremiumSticker);
  3202. document->size = size;
  3203. document->setattributes(attributes);
  3204. // Uses 'type' that is computed from attributes.
  3205. document->recountIsImage();
  3206. if (dc != 0 && access != 0) {
  3207. document->setRemoteLocation(dc, access, fileReference);
  3208. }
  3209. }
  3210. not_null<DocumentData*> Session::venueIconDocument(const QString &icon) {
  3211. const auto i = _venueIcons.find(icon);
  3212. if (i != end(_venueIcons)) {
  3213. return i->second;
  3214. }
  3215. const auto result = documentFromWeb(MTP_webDocumentNoProxy(
  3216. MTP_string(u"https://ss3.4sqi.net/img/categories_v2/"_q
  3217. + icon
  3218. + u"_64.png"_q),
  3219. MTP_int(0),
  3220. MTP_string("image/png"),
  3221. MTP_vector<MTPDocumentAttribute>()), {}, {});
  3222. _venueIcons.emplace(icon, result);
  3223. return result;
  3224. }
  3225. not_null<WebPageData*> Session::webpage(WebPageId id) {
  3226. auto i = _webpages.find(id);
  3227. if (i == _webpages.cend()) {
  3228. i = _webpages.emplace(
  3229. id,
  3230. std::make_unique<WebPageData>(this, id)).first;
  3231. }
  3232. return i->second.get();
  3233. }
  3234. not_null<WebPageData*> Session::processWebpage(const MTPWebPage &data) {
  3235. switch (data.type()) {
  3236. case mtpc_webPage:
  3237. return processWebpage(data.c_webPage());
  3238. case mtpc_webPageEmpty: {
  3239. const auto result = webpage(data.c_webPageEmpty().vid().v);
  3240. result->type = WebPageType::None;
  3241. if (result->pendingTill > 0) {
  3242. result->pendingTill = 0;
  3243. result->failed = 1;
  3244. notifyWebPageUpdateDelayed(result);
  3245. }
  3246. return result;
  3247. } break;
  3248. case mtpc_webPagePending:
  3249. return processWebpage(data.c_webPagePending());
  3250. case mtpc_webPageNotModified:
  3251. LOG(("API Error: "
  3252. "webPageNotModified is unexpected in Session::webpage()."));
  3253. return webpage(0);
  3254. }
  3255. Unexpected("Type in Session::webpage().");
  3256. }
  3257. not_null<WebPageData*> Session::processWebpage(const MTPDwebPage &data) {
  3258. const auto result = webpage(data.vid().v);
  3259. webpageApplyFields(result, data);
  3260. return result;
  3261. }
  3262. not_null<WebPageData*> Session::processWebpage(
  3263. const MTPDwebPagePending &data) {
  3264. constexpr auto kDefaultPendingTimeout = 60;
  3265. const auto result = webpage(data.vid().v);
  3266. webpageApplyFields(
  3267. result,
  3268. WebPageType::None,
  3269. QString(),
  3270. QString(),
  3271. QString(),
  3272. QString(),
  3273. TextWithEntities(),
  3274. FullStoryId(),
  3275. nullptr,
  3276. nullptr,
  3277. WebPageCollage(),
  3278. nullptr,
  3279. nullptr,
  3280. nullptr,
  3281. 0,
  3282. QString(),
  3283. false,
  3284. false,
  3285. data.vdate().v
  3286. ? data.vdate().v
  3287. : (base::unixtime::now() + kDefaultPendingTimeout));
  3288. return result;
  3289. }
  3290. not_null<WebPageData*> Session::webpage(
  3291. WebPageId id,
  3292. const QString &siteName,
  3293. const TextWithEntities &content) {
  3294. return webpage(
  3295. id,
  3296. WebPageType::Article,
  3297. QString(),
  3298. QString(),
  3299. siteName,
  3300. QString(),
  3301. content,
  3302. nullptr,
  3303. nullptr,
  3304. WebPageCollage(),
  3305. nullptr,
  3306. nullptr,
  3307. nullptr,
  3308. 0,
  3309. QString(),
  3310. false,
  3311. false,
  3312. TimeId(0));
  3313. }
  3314. not_null<WebPageData*> Session::webpage(
  3315. WebPageId id,
  3316. WebPageType type,
  3317. const QString &url,
  3318. const QString &displayUrl,
  3319. const QString &siteName,
  3320. const QString &title,
  3321. const TextWithEntities &description,
  3322. PhotoData *photo,
  3323. DocumentData *document,
  3324. WebPageCollage &&collage,
  3325. std::unique_ptr<Iv::Data> iv,
  3326. std::unique_ptr<WebPageStickerSet> stickerSet,
  3327. std::shared_ptr<UniqueGift> uniqueGift,
  3328. int duration,
  3329. const QString &author,
  3330. bool hasLargeMedia,
  3331. bool photoIsVideoCover,
  3332. TimeId pendingTill) {
  3333. const auto result = webpage(id);
  3334. webpageApplyFields(
  3335. result,
  3336. type,
  3337. url,
  3338. displayUrl,
  3339. siteName,
  3340. title,
  3341. description,
  3342. FullStoryId(),
  3343. photo,
  3344. document,
  3345. std::move(collage),
  3346. std::move(iv),
  3347. std::move(stickerSet),
  3348. std::move(uniqueGift),
  3349. duration,
  3350. author,
  3351. hasLargeMedia,
  3352. photoIsVideoCover,
  3353. pendingTill);
  3354. return result;
  3355. }
  3356. void Session::webpageApplyFields(
  3357. not_null<WebPageData*> page,
  3358. const MTPDwebPage &data) {
  3359. auto description = TextWithEntities{
  3360. qs(data.vdescription().value_or_empty())
  3361. };
  3362. const auto siteName = qs(data.vsite_name().value_or_empty());
  3363. auto parseFlags = TextParseLinks | TextParseMultiline;
  3364. if (siteName == u"Twitter"_q || siteName == u"Instagram"_q) {
  3365. parseFlags |= TextParseHashtags | TextParseMentions;
  3366. }
  3367. TextUtilities::ParseEntities(description, parseFlags);
  3368. const auto pendingTill = TimeId(0);
  3369. const auto photo = data.vphoto();
  3370. const auto document = data.vdocument();
  3371. const auto lookupInAttribute = [&](
  3372. const MTPDwebPageAttributeTheme &data) -> DocumentData* {
  3373. if (const auto documents = data.vdocuments()) {
  3374. for (const auto &document : documents->v) {
  3375. const auto processed = processDocument(document);
  3376. if (processed->isTheme()) {
  3377. return processed;
  3378. }
  3379. }
  3380. }
  3381. return nullptr;
  3382. };
  3383. const auto lookupThemeDocument = [&]() -> DocumentData* {
  3384. if (const auto attributes = data.vattributes()) {
  3385. for (const auto &attribute : attributes->v) {
  3386. const auto result = attribute.match([&](
  3387. const MTPDwebPageAttributeTheme &data) {
  3388. return lookupInAttribute(data);
  3389. }, [](const MTPDwebPageAttributeStory &) {
  3390. return (DocumentData*)nullptr;
  3391. }, [](const MTPDwebPageAttributeStickerSet &) {
  3392. return (DocumentData*)nullptr;
  3393. }, [](const MTPDwebPageAttributeUniqueStarGift &) {
  3394. return (DocumentData*)nullptr;
  3395. });
  3396. if (result) {
  3397. return result;
  3398. }
  3399. }
  3400. }
  3401. return nullptr;
  3402. };
  3403. using WebPageStickerSetPtr = std::unique_ptr<WebPageStickerSet>;
  3404. const auto lookupStickerSet = [&]() -> WebPageStickerSetPtr {
  3405. if (const auto attributes = data.vattributes()) {
  3406. for (const auto &attribute : attributes->v) {
  3407. auto result = attribute.match([&](
  3408. const MTPDwebPageAttributeStickerSet &data) {
  3409. auto result = std::make_unique<WebPageStickerSet>();
  3410. result->isEmoji = data.is_emojis();
  3411. result->isTextColor = data.is_text_color();
  3412. for (const auto &tl : data.vstickers().v) {
  3413. result->items.push_back(processDocument(tl));
  3414. }
  3415. return result;
  3416. }, [](const auto &) {
  3417. return WebPageStickerSetPtr(nullptr);
  3418. });
  3419. if (result && !result->items.empty()) {
  3420. return result;
  3421. }
  3422. }
  3423. }
  3424. return nullptr;
  3425. };
  3426. using UniqueGiftPtr = std::shared_ptr<UniqueGift>;
  3427. const auto lookupUniqueGift = [&]() -> UniqueGiftPtr {
  3428. if (const auto attributes = data.vattributes()) {
  3429. for (const auto &attribute : attributes->v) {
  3430. return attribute.match([&](
  3431. const MTPDwebPageAttributeUniqueStarGift &data) {
  3432. const auto gift = Api::FromTL(_session, data.vgift());
  3433. return gift ? gift->unique : nullptr;
  3434. }, [](const auto &) -> UniqueGiftPtr { return nullptr; });
  3435. }
  3436. }
  3437. return nullptr;
  3438. };
  3439. auto story = (Data::Story*)nullptr;
  3440. auto storyId = FullStoryId();
  3441. if (const auto attributes = data.vattributes()) {
  3442. for (const auto &attribute : attributes->v) {
  3443. attribute.match([&](const MTPDwebPageAttributeStory &data) {
  3444. storyId = FullStoryId{
  3445. peerFromMTP(data.vpeer()),
  3446. data.vid().v,
  3447. };
  3448. if (const auto embed = data.vstory()) {
  3449. story = stories().applySingle(
  3450. peerFromMTP(data.vpeer()),
  3451. *embed);
  3452. } else if (const auto maybe = stories().lookup(storyId)) {
  3453. story = *maybe;
  3454. } else if (maybe.error() == Data::NoStory::Unknown) {
  3455. stories().resolve(storyId, [=] {
  3456. if (const auto maybe = stories().lookup(storyId)) {
  3457. const auto story = *maybe;
  3458. page->document = story->document();
  3459. page->photo = story->photo();
  3460. page->description = story->caption();
  3461. page->type = WebPageType::Story;
  3462. notifyWebPageUpdateDelayed(page);
  3463. }
  3464. });
  3465. }
  3466. }, [](const auto &) {});
  3467. }
  3468. }
  3469. if (const auto page = data.vcached_page()) {
  3470. for (const auto &photo : page->data().vphotos().v) {
  3471. processPhoto(photo);
  3472. }
  3473. for (const auto &document : page->data().vdocuments().v) {
  3474. processDocument(document);
  3475. }
  3476. const auto process = [&](
  3477. const MTPPageBlock &block,
  3478. const auto &self) -> void {
  3479. block.match([&](const MTPDpageBlockChannel &data) {
  3480. processChat(data.vchannel());
  3481. }, [&](const MTPDpageBlockCover &data) {
  3482. self(data.vcover(), self);
  3483. }, [&](const MTPDpageBlockEmbedPost &data) {
  3484. for (const auto &block : data.vblocks().v) {
  3485. self(block, self);
  3486. }
  3487. }, [&](const MTPDpageBlockCollage &data) {
  3488. for (const auto &block : data.vitems().v) {
  3489. self(block, self);
  3490. }
  3491. }, [&](const MTPDpageBlockSlideshow &data) {
  3492. for (const auto &block : data.vitems().v) {
  3493. self(block, self);
  3494. }
  3495. }, [&](const MTPDpageBlockDetails &data) {
  3496. for (const auto &block : data.vblocks().v) {
  3497. self(block, self);
  3498. }
  3499. }, [](const auto &) {});
  3500. };
  3501. for (const auto &block : page->data().vblocks().v) {
  3502. process(block, process);
  3503. }
  3504. }
  3505. const auto type = story ? WebPageType::Story : ParseWebPageType(data);
  3506. auto iv = (data.vcached_page() && !IgnoreIv(type))
  3507. ? std::make_unique<Iv::Data>(data, *data.vcached_page())
  3508. : nullptr;
  3509. webpageApplyFields(
  3510. page,
  3511. type,
  3512. qs(data.vurl()),
  3513. qs(data.vdisplay_url()),
  3514. qs(data.vsite_name().value_or_empty()),
  3515. qs(data.vtitle().value_or_empty()),
  3516. (story ? story->caption() : description),
  3517. storyId,
  3518. (story
  3519. ? story->photo()
  3520. : photo
  3521. ? processPhoto(*photo).get()
  3522. : nullptr),
  3523. (story
  3524. ? story->document()
  3525. : document
  3526. ? processDocument(*document).get()
  3527. : lookupThemeDocument()),
  3528. WebPageCollage(this, data),
  3529. std::move(iv),
  3530. lookupStickerSet(),
  3531. lookupUniqueGift(),
  3532. data.vduration().value_or_empty(),
  3533. qs(data.vauthor().value_or_empty()),
  3534. data.is_has_large_media(),
  3535. data.is_video_cover_photo(),
  3536. pendingTill);
  3537. }
  3538. void Session::webpageApplyFields(
  3539. not_null<WebPageData*> page,
  3540. WebPageType type,
  3541. const QString &url,
  3542. const QString &displayUrl,
  3543. const QString &siteName,
  3544. const QString &title,
  3545. const TextWithEntities &description,
  3546. FullStoryId storyId,
  3547. PhotoData *photo,
  3548. DocumentData *document,
  3549. WebPageCollage &&collage,
  3550. std::unique_ptr<Iv::Data> iv,
  3551. std::unique_ptr<WebPageStickerSet> stickerSet,
  3552. std::shared_ptr<UniqueGift> uniqueGift,
  3553. int duration,
  3554. const QString &author,
  3555. bool hasLargeMedia,
  3556. bool photoIsVideoCover,
  3557. TimeId pendingTill) {
  3558. const auto requestPending = (!page->pendingTill && pendingTill > 0);
  3559. const auto changed = page->applyChanges(
  3560. type,
  3561. url,
  3562. displayUrl,
  3563. siteName,
  3564. title,
  3565. description,
  3566. storyId,
  3567. photo,
  3568. document,
  3569. std::move(collage),
  3570. std::move(iv),
  3571. std::move(stickerSet),
  3572. std::move(uniqueGift),
  3573. duration,
  3574. author,
  3575. hasLargeMedia,
  3576. photoIsVideoCover,
  3577. pendingTill);
  3578. if (requestPending) {
  3579. _session->api().requestWebPageDelayed(page);
  3580. }
  3581. if (changed) {
  3582. notifyWebPageUpdateDelayed(page);
  3583. }
  3584. }
  3585. not_null<GameData*> Session::game(GameId id) {
  3586. auto i = _games.find(id);
  3587. if (i == _games.cend()) {
  3588. i = _games.emplace(id, std::make_unique<GameData>(this, id)).first;
  3589. }
  3590. return i->second.get();
  3591. }
  3592. not_null<GameData*> Session::processGame(const MTPDgame &data) {
  3593. const auto result = game(data.vid().v);
  3594. gameApplyFields(result, data);
  3595. return result;
  3596. }
  3597. not_null<GameData*> Session::game(
  3598. GameId id,
  3599. const uint64 &accessHash,
  3600. const QString &shortName,
  3601. const QString &title,
  3602. const QString &description,
  3603. PhotoData *photo,
  3604. DocumentData *document) {
  3605. const auto result = game(id);
  3606. gameApplyFields(
  3607. result,
  3608. accessHash,
  3609. shortName,
  3610. title,
  3611. description,
  3612. photo,
  3613. document);
  3614. return result;
  3615. }
  3616. void Session::gameConvert(
  3617. not_null<GameData*> original,
  3618. const MTPGame &data) {
  3619. Expects(data.type() == mtpc_game);
  3620. const auto id = data.c_game().vid().v;
  3621. if (original->id != id) {
  3622. auto i = _games.find(id);
  3623. if (i == _games.end()) {
  3624. const auto j = _games.find(original->id);
  3625. Assert(j != _games.end());
  3626. auto owned = std::move(j->second);
  3627. _games.erase(j);
  3628. i = _games.emplace(id, std::move(owned)).first;
  3629. }
  3630. original->id = id;
  3631. original->accessHash = 0;
  3632. if (i->second.get() != original) {
  3633. gameApplyFields(i->second.get(), data.c_game());
  3634. }
  3635. }
  3636. gameApplyFields(original, data.c_game());
  3637. }
  3638. void Session::gameApplyFields(
  3639. not_null<GameData*> game,
  3640. const MTPDgame &data) {
  3641. const auto document = data.vdocument();
  3642. gameApplyFields(
  3643. game,
  3644. data.vaccess_hash().v,
  3645. qs(data.vshort_name()),
  3646. qs(data.vtitle()),
  3647. qs(data.vdescription()),
  3648. processPhoto(data.vphoto()),
  3649. document ? processDocument(*document).get() : nullptr);
  3650. }
  3651. void Session::gameApplyFields(
  3652. not_null<GameData*> game,
  3653. const uint64 &accessHash,
  3654. const QString &shortName,
  3655. const QString &title,
  3656. const QString &description,
  3657. PhotoData *photo,
  3658. DocumentData *document) {
  3659. if (game->accessHash) {
  3660. return;
  3661. }
  3662. game->accessHash = accessHash;
  3663. game->shortName = shortName;
  3664. game->title = TextUtilities::SingleLine(title);
  3665. game->description = description;
  3666. game->photo = photo;
  3667. game->document = document;
  3668. notifyGameUpdateDelayed(game);
  3669. }
  3670. not_null<BotAppData*> Session::botApp(BotAppId id) {
  3671. const auto i = _botApps.find(id);
  3672. return (i != end(_botApps))
  3673. ? i->second.get()
  3674. : _botApps.emplace(
  3675. id,
  3676. std::make_unique<BotAppData>(this, id)).first->second.get();
  3677. }
  3678. BotAppData *Session::findBotApp(PeerId botId, const QString &appName) const {
  3679. for (const auto &[id, app] : _botApps) {
  3680. if (app->botId == botId && app->shortName == appName) {
  3681. return app.get();
  3682. }
  3683. }
  3684. return nullptr;
  3685. }
  3686. BotAppData *Session::processBotApp(
  3687. PeerId botId,
  3688. const MTPBotApp &data) {
  3689. return data.match([&](const MTPDbotApp &data) {
  3690. const auto result = botApp(data.vid().v);
  3691. result->botId = botId;
  3692. result->shortName = qs(data.vshort_name());
  3693. result->title = qs(data.vtitle());
  3694. result->description = qs(data.vdescription());
  3695. result->photo = processPhoto(data.vphoto());
  3696. result->document = data.vdocument()
  3697. ? processDocument(*data.vdocument()).get()
  3698. : nullptr;
  3699. result->accessHash = data.vaccess_hash().v;
  3700. result->hash = data.vhash().v;
  3701. return result.get();
  3702. }, [](const MTPDbotAppNotModified &) {
  3703. return (BotAppData*)nullptr;
  3704. });
  3705. }
  3706. not_null<PollData*> Session::poll(PollId id) {
  3707. auto i = _polls.find(id);
  3708. if (i == _polls.cend()) {
  3709. i = _polls.emplace(id, std::make_unique<PollData>(this, id)).first;
  3710. }
  3711. return i->second.get();
  3712. }
  3713. not_null<PollData*> Session::processPoll(const MTPPoll &data) {
  3714. return data.match([&](const MTPDpoll &data) {
  3715. const auto id = data.vid().v;
  3716. const auto result = poll(id);
  3717. const auto changed = result->applyChanges(data);
  3718. if (changed) {
  3719. notifyPollUpdateDelayed(result);
  3720. }
  3721. if (result->closeDate > 0 && !result->closed()) {
  3722. _pollsClosings.emplace(result->closeDate, result);
  3723. checkPollsClosings();
  3724. }
  3725. return result;
  3726. });
  3727. }
  3728. not_null<PollData*> Session::processPoll(const MTPDmessageMediaPoll &data) {
  3729. const auto result = processPoll(data.vpoll());
  3730. const auto changed = result->applyResults(data.vresults());
  3731. if (changed) {
  3732. notifyPollUpdateDelayed(result);
  3733. }
  3734. return result;
  3735. }
  3736. void Session::checkPollsClosings() {
  3737. const auto now = base::unixtime::now();
  3738. auto closest = 0;
  3739. for (auto i = _pollsClosings.begin(); i != _pollsClosings.end();) {
  3740. if (i->first <= now) {
  3741. if (i->second->closeByTimer()) {
  3742. notifyPollUpdateDelayed(i->second);
  3743. }
  3744. i = _pollsClosings.erase(i);
  3745. } else {
  3746. if (!closest) {
  3747. closest = i->first;
  3748. }
  3749. ++i;
  3750. }
  3751. }
  3752. if (closest) {
  3753. _pollsClosingTimer.callOnce((closest - now) * crl::time(1000));
  3754. } else {
  3755. _pollsClosingTimer.cancel();
  3756. }
  3757. }
  3758. void Session::applyUpdate(const MTPDupdateMessagePoll &update) {
  3759. const auto updated = [&] {
  3760. const auto poll = update.vpoll();
  3761. const auto i = _polls.find(update.vpoll_id().v);
  3762. return (i == end(_polls))
  3763. ? nullptr
  3764. : poll
  3765. ? processPoll(*poll).get()
  3766. : i->second.get();
  3767. }();
  3768. if (updated && updated->applyResults(update.vresults())) {
  3769. notifyPollUpdateDelayed(updated);
  3770. }
  3771. }
  3772. void Session::applyUpdate(const MTPDupdateChatParticipants &update) {
  3773. const auto chatId = update.vparticipants().match([](const auto &update) {
  3774. return update.vchat_id().v;
  3775. });
  3776. if (const auto chat = chatLoaded(chatId)) {
  3777. ApplyChatUpdate(chat, update);
  3778. for (const auto &user : chat->participants) {
  3779. if (user->isBot() && !user->botInfo->inited) {
  3780. _session->api().requestFullPeer(user);
  3781. }
  3782. }
  3783. }
  3784. }
  3785. void Session::applyUpdate(const MTPDupdateChatParticipantAdd &update) {
  3786. if (const auto chat = chatLoaded(update.vchat_id().v)) {
  3787. ApplyChatUpdate(chat, update);
  3788. }
  3789. }
  3790. void Session::applyUpdate(const MTPDupdateChatParticipantDelete &update) {
  3791. if (const auto chat = chatLoaded(update.vchat_id().v)) {
  3792. ApplyChatUpdate(chat, update);
  3793. }
  3794. }
  3795. void Session::applyUpdate(const MTPDupdateChatParticipantAdmin &update) {
  3796. if (const auto chat = chatLoaded(update.vchat_id().v)) {
  3797. ApplyChatUpdate(chat, update);
  3798. }
  3799. }
  3800. void Session::applyUpdate(const MTPDupdateChatDefaultBannedRights &update) {
  3801. if (const auto peer = peerLoaded(peerFromMTP(update.vpeer()))) {
  3802. if (const auto chat = peer->asChat()) {
  3803. ApplyChatUpdate(chat, update);
  3804. } else if (const auto channel = peer->asChannel()) {
  3805. ApplyChannelUpdate(channel, update);
  3806. } else {
  3807. LOG(("API Error: "
  3808. "User received in updateChatDefaultBannedRights."));
  3809. }
  3810. }
  3811. }
  3812. not_null<Data::CloudImage*> Session::location(const LocationPoint &point) {
  3813. const auto i = _locations.find(point);
  3814. if (i != _locations.cend()) {
  3815. return i->second.get();
  3816. }
  3817. const auto location = Data::ComputeLocation(point);
  3818. const auto prepared = ImageWithLocation{
  3819. .location = ImageLocation(
  3820. { location },
  3821. location.width,
  3822. location.height)
  3823. };
  3824. return _locations.emplace(
  3825. point,
  3826. std::make_unique<Data::CloudImage>(
  3827. _session,
  3828. prepared)).first->second.get();
  3829. }
  3830. void Session::registerPhotoItem(
  3831. not_null<const PhotoData*> photo,
  3832. not_null<HistoryItem*> item) {
  3833. _photoItems[photo].insert(item);
  3834. }
  3835. void Session::unregisterPhotoItem(
  3836. not_null<const PhotoData*> photo,
  3837. not_null<HistoryItem*> item) {
  3838. const auto i = _photoItems.find(photo);
  3839. if (i != _photoItems.end()) {
  3840. auto &items = i->second;
  3841. if (items.remove(item) && items.empty()) {
  3842. _photoItems.erase(i);
  3843. }
  3844. }
  3845. }
  3846. void Session::registerDocumentItem(
  3847. not_null<const DocumentData*> document,
  3848. not_null<HistoryItem*> item) {
  3849. _documentItems[document].insert(item);
  3850. }
  3851. void Session::unregisterDocumentItem(
  3852. not_null<const DocumentData*> document,
  3853. not_null<HistoryItem*> item) {
  3854. const auto i = _documentItems.find(document);
  3855. if (i != _documentItems.end()) {
  3856. auto &items = i->second;
  3857. if (items.remove(item) && items.empty()) {
  3858. _documentItems.erase(i);
  3859. }
  3860. }
  3861. }
  3862. void Session::registerWebPageView(
  3863. not_null<const WebPageData*> page,
  3864. not_null<ViewElement*> view) {
  3865. _webpageViews[page].insert(view);
  3866. }
  3867. void Session::unregisterWebPageView(
  3868. not_null<const WebPageData*> page,
  3869. not_null<ViewElement*> view) {
  3870. const auto i = _webpageViews.find(page);
  3871. if (i != _webpageViews.end()) {
  3872. auto &items = i->second;
  3873. if (items.remove(view) && items.empty()) {
  3874. _webpageViews.erase(i);
  3875. }
  3876. }
  3877. }
  3878. void Session::registerWebPageItem(
  3879. not_null<const WebPageData*> page,
  3880. not_null<HistoryItem*> item) {
  3881. _webpageItems[page].insert(item);
  3882. }
  3883. void Session::unregisterWebPageItem(
  3884. not_null<const WebPageData*> page,
  3885. not_null<HistoryItem*> item) {
  3886. const auto i = _webpageItems.find(page);
  3887. if (i != _webpageItems.end()) {
  3888. auto &items = i->second;
  3889. if (items.remove(item) && items.empty()) {
  3890. _webpageItems.erase(i);
  3891. }
  3892. }
  3893. }
  3894. void Session::registerGameView(
  3895. not_null<const GameData*> game,
  3896. not_null<ViewElement*> view) {
  3897. _gameViews[game].insert(view);
  3898. }
  3899. void Session::unregisterGameView(
  3900. not_null<const GameData*> game,
  3901. not_null<ViewElement*> view) {
  3902. const auto i = _gameViews.find(game);
  3903. if (i != _gameViews.end()) {
  3904. auto &items = i->second;
  3905. if (items.remove(view) && items.empty()) {
  3906. _gameViews.erase(i);
  3907. }
  3908. }
  3909. }
  3910. void Session::registerPollView(
  3911. not_null<const PollData*> poll,
  3912. not_null<ViewElement*> view) {
  3913. _pollViews[poll].insert(view);
  3914. }
  3915. void Session::unregisterPollView(
  3916. not_null<const PollData*> poll,
  3917. not_null<ViewElement*> view) {
  3918. const auto i = _pollViews.find(poll);
  3919. if (i != _pollViews.end()) {
  3920. auto &items = i->second;
  3921. if (items.remove(view) && items.empty()) {
  3922. _pollViews.erase(i);
  3923. }
  3924. }
  3925. }
  3926. void Session::registerContactView(
  3927. UserId contactId,
  3928. not_null<ViewElement*> view) {
  3929. if (!contactId) {
  3930. return;
  3931. }
  3932. _contactViews[contactId].insert(view);
  3933. }
  3934. void Session::unregisterContactView(
  3935. UserId contactId,
  3936. not_null<ViewElement*> view) {
  3937. if (!contactId) {
  3938. return;
  3939. }
  3940. const auto i = _contactViews.find(contactId);
  3941. if (i != _contactViews.end()) {
  3942. auto &items = i->second;
  3943. if (items.remove(view) && items.empty()) {
  3944. _contactViews.erase(i);
  3945. }
  3946. }
  3947. }
  3948. void Session::registerContactItem(
  3949. UserId contactId,
  3950. not_null<HistoryItem*> item) {
  3951. if (!contactId) {
  3952. return;
  3953. }
  3954. const auto contact = userLoaded(contactId);
  3955. const auto canShare = contact ? contact->canShareThisContact() : false;
  3956. _contactItems[contactId].insert(item);
  3957. if (contact && canShare != contact->canShareThisContact()) {
  3958. session().changes().peerUpdated(
  3959. contact,
  3960. PeerUpdate::Flag::CanShareContact);
  3961. }
  3962. if (const auto i = _views.find(item); i != _views.end()) {
  3963. for (const auto view : i->second) {
  3964. if (const auto media = view->media()) {
  3965. media->updateSharedContactUserId(contactId);
  3966. }
  3967. }
  3968. }
  3969. }
  3970. void Session::unregisterContactItem(
  3971. UserId contactId,
  3972. not_null<HistoryItem*> item) {
  3973. if (!contactId) {
  3974. return;
  3975. }
  3976. const auto contact = userLoaded(contactId);
  3977. const auto canShare = contact ? contact->canShareThisContact() : false;
  3978. const auto i = _contactItems.find(contactId);
  3979. if (i != _contactItems.end()) {
  3980. auto &items = i->second;
  3981. if (items.remove(item) && items.empty()) {
  3982. _contactItems.erase(i);
  3983. }
  3984. }
  3985. if (contact && canShare != contact->canShareThisContact()) {
  3986. session().changes().peerUpdated(
  3987. contact,
  3988. PeerUpdate::Flag::CanShareContact);
  3989. }
  3990. }
  3991. void Session::registerCallItem(not_null<HistoryItem*> item) {
  3992. _callItems.emplace(item);
  3993. }
  3994. void Session::unregisterCallItem(not_null<HistoryItem*> item) {
  3995. _callItems.erase(item);
  3996. }
  3997. void Session::destroyAllCallItems() {
  3998. while (!_callItems.empty()) {
  3999. (*_callItems.begin())->destroy();
  4000. }
  4001. }
  4002. void Session::registerStoryItem(
  4003. FullStoryId id,
  4004. not_null<HistoryItem*> item) {
  4005. _storyItems[id].emplace(item);
  4006. }
  4007. void Session::unregisterStoryItem(
  4008. FullStoryId id,
  4009. not_null<HistoryItem*> item) {
  4010. const auto i = _storyItems.find(id);
  4011. if (i != _storyItems.end()) {
  4012. auto &items = i->second;
  4013. if (items.remove(item) && items.empty()) {
  4014. _storyItems.erase(i);
  4015. }
  4016. }
  4017. }
  4018. void Session::refreshStoryItemViews(FullStoryId id) {
  4019. const auto i = _storyItems.find(id);
  4020. if (i != _storyItems.end()) {
  4021. for (const auto item : i->second) {
  4022. if (const auto media = item->media()) {
  4023. if (media->storyMention()) {
  4024. item->updateStoryMentionText();
  4025. }
  4026. }
  4027. requestItemViewRefresh(item);
  4028. }
  4029. }
  4030. }
  4031. void Session::documentMessageRemoved(not_null<DocumentData*> document) {
  4032. if (_documentItems.find(document) != _documentItems.end()) {
  4033. return;
  4034. }
  4035. if (document->loading()) {
  4036. document->cancel();
  4037. }
  4038. }
  4039. void Session::checkPlayingAnimations() {
  4040. auto check = base::flat_set<not_null<ViewElement*>>();
  4041. for (const auto &view : _heavyViewParts) {
  4042. if (const auto media = view->media()) {
  4043. if (const auto document = media->getDocument()) {
  4044. if (document->isAnimation() || document->isVideoFile()) {
  4045. check.emplace(view);
  4046. }
  4047. } else if (const auto photo = media->getPhoto()) {
  4048. if (photo->hasVideo()) {
  4049. check.emplace(view);
  4050. }
  4051. }
  4052. }
  4053. }
  4054. for (const auto &view : check) {
  4055. view->media()->checkAnimation();
  4056. }
  4057. }
  4058. HistoryItem *Session::findWebPageItem(not_null<WebPageData*> page) const {
  4059. const auto i = _webpageItems.find(page);
  4060. if (i != _webpageItems.end()) {
  4061. for (const auto &item : i->second) {
  4062. if (item->isRegular()) {
  4063. return item;
  4064. }
  4065. }
  4066. }
  4067. return nullptr;
  4068. }
  4069. QString Session::findContactPhone(not_null<UserData*> contact) const {
  4070. const auto result = contact->phone();
  4071. return result.isEmpty()
  4072. ? findContactPhone(peerToUser(contact->id))
  4073. : Ui::FormatPhone(result);
  4074. }
  4075. QString Session::findContactPhone(UserId contactId) const {
  4076. const auto i = _contactItems.find(contactId);
  4077. if (i != _contactItems.end()) {
  4078. if (const auto media = (*begin(i->second))->media()) {
  4079. if (const auto contact = media->sharedContact()) {
  4080. return contact->phoneNumber;
  4081. }
  4082. }
  4083. }
  4084. return QString();
  4085. }
  4086. bool Session::hasPendingWebPageGamePollNotification() const {
  4087. return !_webpagesUpdated.empty()
  4088. || !_gamesUpdated.empty()
  4089. || !_pollsUpdated.empty();
  4090. }
  4091. void Session::notifyWebPageUpdateDelayed(not_null<WebPageData*> page) {
  4092. const auto invoke = !hasPendingWebPageGamePollNotification();
  4093. _webpagesUpdated.insert(page);
  4094. if (invoke) {
  4095. crl::on_main(_session, [=] { sendWebPageGamePollNotifications(); });
  4096. }
  4097. }
  4098. void Session::notifyGameUpdateDelayed(not_null<GameData*> game) {
  4099. const auto invoke = !hasPendingWebPageGamePollNotification();
  4100. _gamesUpdated.insert(game);
  4101. if (invoke) {
  4102. crl::on_main(_session, [=] { sendWebPageGamePollNotifications(); });
  4103. }
  4104. }
  4105. void Session::notifyPollUpdateDelayed(not_null<PollData*> poll) {
  4106. const auto invoke = !hasPendingWebPageGamePollNotification();
  4107. _pollsUpdated.insert(poll);
  4108. if (invoke) {
  4109. crl::on_main(_session, [=] { sendWebPageGamePollNotifications(); });
  4110. }
  4111. }
  4112. void Session::sendWebPageGamePollNotifications() {
  4113. auto resize = std::vector<not_null<ViewElement*>>();
  4114. for (const auto &page : base::take(_webpagesUpdated)) {
  4115. _webpageUpdates.fire_copy(page);
  4116. if (const auto i = _webpageViews.find(page)
  4117. ; i != _webpageViews.end()) {
  4118. resize.insert(end(resize), begin(i->second), end(i->second));
  4119. }
  4120. }
  4121. for (const auto &game : base::take(_gamesUpdated)) {
  4122. if (const auto i = _gameViews.find(game); i != _gameViews.end()) {
  4123. resize.insert(end(resize), begin(i->second), end(i->second));
  4124. }
  4125. }
  4126. for (const auto &poll : base::take(_pollsUpdated)) {
  4127. if (const auto i = _pollViews.find(poll); i != _pollViews.end()) {
  4128. resize.insert(end(resize), begin(i->second), end(i->second));
  4129. }
  4130. }
  4131. for (const auto &view : resize) {
  4132. requestViewResize(view);
  4133. }
  4134. }
  4135. rpl::producer<not_null<WebPageData*>> Session::webPageUpdates() const {
  4136. return _webpageUpdates.events();
  4137. }
  4138. void Session::channelDifferenceTooLong(not_null<ChannelData*> channel) {
  4139. _channelDifferenceTooLong.fire_copy(channel);
  4140. }
  4141. rpl::producer<not_null<ChannelData*>> Session::channelDifferenceTooLong() const {
  4142. return _channelDifferenceTooLong.events();
  4143. }
  4144. void Session::registerItemView(not_null<ViewElement*> view) {
  4145. _views[view->data()].push_back(view);
  4146. }
  4147. void Session::unregisterItemView(not_null<ViewElement*> view) {
  4148. Expects(!_heavyViewParts.contains(view));
  4149. _shownSpoilers.remove(view);
  4150. const auto i = _views.find(view->data());
  4151. if (i != end(_views)) {
  4152. auto &list = i->second;
  4153. list.erase(ranges::remove(list, view), end(list));
  4154. if (list.empty()) {
  4155. _views.erase(i);
  4156. }
  4157. }
  4158. using namespace HistoryView;
  4159. if (Element::Hovered() == view) {
  4160. Element::Hovered(nullptr);
  4161. }
  4162. if (Element::Pressed() == view) {
  4163. Element::Pressed(nullptr);
  4164. }
  4165. if (Element::HoveredLink() == view) {
  4166. Element::HoveredLink(nullptr);
  4167. }
  4168. if (Element::PressedLink() == view) {
  4169. Element::PressedLink(nullptr);
  4170. }
  4171. if (Element::Moused() == view) {
  4172. Element::Moused(nullptr);
  4173. }
  4174. }
  4175. not_null<Folder*> Session::folder(FolderId id) {
  4176. if (const auto result = folderLoaded(id)) {
  4177. return result;
  4178. }
  4179. const auto &[it, ok] = _folders.emplace(
  4180. id,
  4181. std::make_unique<Folder>(this, id));
  4182. return it->second.get();
  4183. }
  4184. Folder *Session::folderLoaded(FolderId id) const {
  4185. const auto it = _folders.find(id);
  4186. return (it == end(_folders)) ? nullptr : it->second.get();
  4187. }
  4188. not_null<Folder*> Session::processFolder(const MTPFolder &data) {
  4189. return data.match([&](const MTPDfolder &data) {
  4190. return processFolder(data);
  4191. });
  4192. }
  4193. not_null<Folder*> Session::processFolder(const MTPDfolder &data) {
  4194. return folder(data.vid().v);
  4195. }
  4196. not_null<Dialogs::MainList*> Session::chatsListFor(
  4197. not_null<Dialogs::Entry*> entry) {
  4198. const auto topic = entry->asTopic();
  4199. return topic
  4200. ? topic->forum()->topicsList()
  4201. : entry->asSublist()
  4202. ? _savedMessages->chatsList()
  4203. : chatsList(entry->folder());
  4204. }
  4205. not_null<Dialogs::MainList*> Session::chatsList(Data::Folder *folder) {
  4206. return folder ? folder->chatsList().get() : &_chatsList;
  4207. }
  4208. not_null<const Dialogs::MainList*> Session::chatsList(
  4209. Data::Folder *folder) const {
  4210. return folder ? folder->chatsList() : &_chatsList;
  4211. }
  4212. not_null<Dialogs::IndexedList*> Session::contactsList() {
  4213. return &_contactsList;
  4214. }
  4215. not_null<Dialogs::IndexedList*> Session::contactsNoChatsList() {
  4216. return &_contactsNoChatsList;
  4217. }
  4218. void Session::refreshChatListEntry(Dialogs::Key key) {
  4219. Expects(key.entry()->folderKnown());
  4220. using namespace Dialogs;
  4221. const auto entry = key.entry();
  4222. const auto history = entry->asHistory();
  4223. const auto topic = entry->asTopic();
  4224. const auto mainList = chatsListFor(entry);
  4225. auto event = ChatListEntryRefresh{ .key = key };
  4226. const auto creating = event.existenceChanged = !entry->inChatList();
  4227. if (creating && topic && topic->creating()) {
  4228. return;
  4229. } else if (event.existenceChanged) {
  4230. const auto mainRow = entry->addToChatList(0, mainList);
  4231. _contactsNoChatsList.remove(key, mainRow);
  4232. } else {
  4233. event.moved = entry->adjustByPosInChatList(0, mainList);
  4234. }
  4235. if (event) {
  4236. _chatListEntryRefreshes.fire(std::move(event));
  4237. }
  4238. if (!history) {
  4239. return;
  4240. }
  4241. for (const auto &filter : _chatsFilters->list()) {
  4242. const auto id = filter.id();
  4243. if (!id) {
  4244. continue;
  4245. }
  4246. const auto filterList = chatsFilters().chatsList(id);
  4247. auto event = ChatListEntryRefresh{ .key = key, .filterId = id };
  4248. if (filter.contains(history)) {
  4249. event.existenceChanged = !entry->inChatList(id);
  4250. if (event.existenceChanged) {
  4251. entry->addToChatList(id, filterList);
  4252. } else {
  4253. event.moved = entry->adjustByPosInChatList(id, filterList);
  4254. }
  4255. } else if (entry->inChatList(id)) {
  4256. entry->removeFromChatList(id, filterList);
  4257. event.existenceChanged = true;
  4258. }
  4259. if (event) {
  4260. _chatListEntryRefreshes.fire(std::move(event));
  4261. }
  4262. }
  4263. if (creating) {
  4264. if (const auto from = history->peer->migrateFrom()) {
  4265. if (const auto migrated = historyLoaded(from)) {
  4266. removeChatListEntry(migrated);
  4267. }
  4268. }
  4269. if (const auto forum = history->peer->forum()) {
  4270. forum->preloadTopics();
  4271. }
  4272. }
  4273. }
  4274. void Session::removeChatListEntry(Dialogs::Key key) {
  4275. using namespace Dialogs;
  4276. const auto entry = key.entry();
  4277. if (!entry->inChatList()) {
  4278. return;
  4279. }
  4280. Assert(entry->folderKnown());
  4281. for (const auto &filter : _chatsFilters->list()) {
  4282. const auto id = filter.id();
  4283. if (id && entry->inChatList(id)) {
  4284. entry->removeFromChatList(id, chatsFilters().chatsList(id));
  4285. _chatListEntryRefreshes.fire(ChatListEntryRefresh{
  4286. .key = key,
  4287. .filterId = id,
  4288. .existenceChanged = true
  4289. });
  4290. }
  4291. }
  4292. const auto mainList = chatsListFor(entry);
  4293. entry->removeFromChatList(0, mainList);
  4294. _chatListEntryRefreshes.fire(ChatListEntryRefresh{
  4295. .key = key,
  4296. .existenceChanged = true
  4297. });
  4298. if (_contactsList.contains(key)) {
  4299. if (!_contactsNoChatsList.contains(key)) {
  4300. _contactsNoChatsList.addByName(key);
  4301. }
  4302. }
  4303. if (const auto topic = key.topic()) {
  4304. Core::App().notifications().clearFromTopic(topic);
  4305. } else if (const auto history = key.history()) {
  4306. Core::App().notifications().clearFromHistory(history);
  4307. }
  4308. }
  4309. auto Session::chatListEntryRefreshes() const
  4310. -> rpl::producer<ChatListEntryRefresh> {
  4311. return _chatListEntryRefreshes.events();
  4312. }
  4313. void Session::dialogsRowReplaced(DialogsRowReplacement replacement) {
  4314. _dialogsRowReplacements.fire(std::move(replacement));
  4315. }
  4316. auto Session::dialogsRowReplacements() const
  4317. -> rpl::producer<DialogsRowReplacement> {
  4318. return _dialogsRowReplacements.events();
  4319. }
  4320. void Session::serviceNotification(
  4321. const TextWithEntities &message,
  4322. const MTPMessageMedia &media,
  4323. bool invertMedia) {
  4324. const auto date = base::unixtime::now();
  4325. if (!peerLoaded(PeerData::kServiceNotificationsId)) {
  4326. processUser(MTP_user(
  4327. MTP_flags(
  4328. MTPDuser::Flag::f_first_name
  4329. | MTPDuser::Flag::f_phone
  4330. | MTPDuser::Flag::f_status
  4331. | MTPDuser::Flag::f_verified),
  4332. MTP_long(peerToUser(PeerData::kServiceNotificationsId).bare),
  4333. MTPlong(), // access_hash
  4334. MTP_string("Telegram"),
  4335. MTPstring(), // last_name
  4336. MTPstring(), // username
  4337. MTP_string("42777"),
  4338. MTP_userProfilePhotoEmpty(),
  4339. MTP_userStatusRecently(MTP_flags(0)),
  4340. MTPint(), // bot_info_version
  4341. MTPVector<MTPRestrictionReason>(),
  4342. MTPstring(), // bot_inline_placeholder
  4343. MTPstring(), // lang_code
  4344. MTPEmojiStatus(),
  4345. MTPVector<MTPUsername>(),
  4346. MTPint(), // stories_max_id
  4347. MTPPeerColor(), // color
  4348. MTPPeerColor(), // profile_color
  4349. MTPint(), // bot_active_users
  4350. MTPlong(), // bot_verification_icon
  4351. MTPlong())); // send_paid_messages_stars
  4352. }
  4353. const auto history = this->history(PeerData::kServiceNotificationsId);
  4354. const auto insert = [=] {
  4355. insertCheckedServiceNotification(message, media, date, invertMedia);
  4356. };
  4357. if (!history->folderKnown()) {
  4358. histories().requestDialogEntry(history, insert);
  4359. } else {
  4360. insert();
  4361. }
  4362. }
  4363. void Session::insertCheckedServiceNotification(
  4364. const TextWithEntities &message,
  4365. const MTPMessageMedia &media,
  4366. TimeId date,
  4367. bool invertMedia) {
  4368. const auto flags = MTPDmessage::Flag::f_entities
  4369. | MTPDmessage::Flag::f_from_id
  4370. | MTPDmessage::Flag::f_media
  4371. | (invertMedia
  4372. ? MTPDmessage::Flag::f_invert_media
  4373. : MTPDmessage::Flag());
  4374. const auto localFlags = MessageFlag::ClientSideUnread
  4375. | MessageFlag::Local;
  4376. auto sending = TextWithEntities(), left = message;
  4377. while (TextUtilities::CutPart(sending, left, MaxMessageSize)) {
  4378. const auto id = nextLocalMessageId();
  4379. addNewMessage(
  4380. id,
  4381. MTP_message(
  4382. MTP_flags(flags),
  4383. MTP_int(0), // Not used (would've been trimmed to 32 bits).
  4384. peerToMTP(PeerData::kServiceNotificationsId),
  4385. MTPint(), // from_boosts_applied
  4386. peerToMTP(PeerData::kServiceNotificationsId),
  4387. MTPPeer(), // saved_peer_id
  4388. MTPMessageFwdHeader(),
  4389. MTPlong(), // via_bot_id
  4390. MTPlong(), // via_business_bot_id
  4391. MTPMessageReplyHeader(),
  4392. MTP_int(date),
  4393. MTP_string(sending.text),
  4394. media,
  4395. MTPReplyMarkup(),
  4396. Api::EntitiesToMTP(&session(), sending.entities),
  4397. MTPint(), // views
  4398. MTPint(), // forwards
  4399. MTPMessageReplies(),
  4400. MTPint(), // edit_date
  4401. MTPstring(),
  4402. MTPlong(),
  4403. MTPMessageReactions(),
  4404. MTPVector<MTPRestrictionReason>(),
  4405. MTPint(), // ttl_period
  4406. MTPint(), // quick_reply_shortcut_id
  4407. MTPlong(), // effect
  4408. MTPFactCheck(),
  4409. MTPint(), // report_delivery_until_date
  4410. MTPlong()), // paid_message_stars
  4411. localFlags,
  4412. NewMessageType::Unread);
  4413. }
  4414. sendHistoryChangeNotifications();
  4415. }
  4416. void Session::setMimeForwardIds(MessageIdsList &&list) {
  4417. _mimeForwardIds = std::move(list);
  4418. }
  4419. MessageIdsList Session::takeMimeForwardIds() {
  4420. return std::move(_mimeForwardIds);
  4421. }
  4422. void Session::setTopPromoted(
  4423. History *promoted,
  4424. const QString &type,
  4425. const QString &message) {
  4426. const auto changed = (_topPromoted != promoted);
  4427. if (!changed
  4428. && (!promoted || promoted->topPromotionMessage() == message)) {
  4429. return;
  4430. }
  4431. if (changed) {
  4432. if (_topPromoted) {
  4433. _topPromoted->cacheTopPromotion(false, QString(), QString());
  4434. }
  4435. }
  4436. const auto old = std::exchange(_topPromoted, promoted);
  4437. if (_topPromoted) {
  4438. histories().requestDialogEntry(_topPromoted);
  4439. _topPromoted->cacheTopPromotion(true, type, message);
  4440. _topPromoted->requestChatListMessage();
  4441. session().changes().historyUpdated(
  4442. _topPromoted,
  4443. HistoryUpdate::Flag::TopPromoted);
  4444. }
  4445. if (changed && old) {
  4446. session().changes().historyUpdated(
  4447. old,
  4448. HistoryUpdate::Flag::TopPromoted);
  4449. }
  4450. }
  4451. bool Session::updateWallpapers(const MTPaccount_WallPapers &data) {
  4452. return data.match([&](const MTPDaccount_wallPapers &data) {
  4453. setWallpapers(data.vwallpapers().v, data.vhash().v);
  4454. return true;
  4455. }, [&](const MTPDaccount_wallPapersNotModified &) {
  4456. return false;
  4457. });
  4458. }
  4459. void Session::setWallpapers(const QVector<MTPWallPaper> &data, uint64 hash) {
  4460. _wallpapersHash = hash;
  4461. _wallpapers.clear();
  4462. _wallpapers.reserve(data.size() + 2);
  4463. _wallpapers.push_back(Data::Legacy1DefaultWallPaper());
  4464. _wallpapers.back().setLocalImageAsThumbnail(std::make_shared<Image>(
  4465. u":/gui/art/bg_initial.jpg"_q));
  4466. for (const auto &paper : data) {
  4467. if (const auto parsed = Data::WallPaper::Create(&session(), paper)) {
  4468. _wallpapers.push_back(*parsed);
  4469. }
  4470. }
  4471. // Put the legacy2 (flowers) wallpaper to the front of the list.
  4472. const auto legacy2 = ranges::find_if(
  4473. _wallpapers,
  4474. Data::IsLegacy2DefaultWallPaper);
  4475. if (legacy2 != end(_wallpapers)) {
  4476. ranges::rotate(begin(_wallpapers), legacy2, legacy2 + 1);
  4477. }
  4478. // Put the legacy3 (static gradient) wallpaper to the front of the list.
  4479. const auto legacy3 = ranges::find_if(
  4480. _wallpapers,
  4481. Data::IsLegacy3DefaultWallPaper);
  4482. if (legacy3 != end(_wallpapers)) {
  4483. ranges::rotate(begin(_wallpapers), legacy3, legacy3 + 1);
  4484. }
  4485. if (ranges::none_of(_wallpapers, Data::IsDefaultWallPaper)) {
  4486. _wallpapers.push_back(Data::DefaultWallPaper());
  4487. _wallpapers.back().setLocalImageAsThumbnail(std::make_shared<Image>(
  4488. u":/gui/art/bg_thumbnail.png"_q));
  4489. }
  4490. }
  4491. void Session::removeWallpaper(const WallPaper &paper) {
  4492. const auto i = ranges::find(_wallpapers, paper.id(), &WallPaper::id);
  4493. if (i != end(_wallpapers)) {
  4494. _wallpapers.erase(i);
  4495. }
  4496. }
  4497. const std::vector<WallPaper> &Session::wallpapers() const {
  4498. return _wallpapers;
  4499. }
  4500. uint64 Session::wallpapersHash() const {
  4501. return _wallpapersHash;
  4502. }
  4503. MTP::DcId Session::statsDcId(not_null<PeerData*> peer) {
  4504. const auto it = _peerStatsDcIds.find(peer);
  4505. return (it == end(_peerStatsDcIds)) ? MTP::DcId(0) : it->second;
  4506. }
  4507. void Session::applyStatsDcId(
  4508. not_null<PeerData*> peer,
  4509. MTP::DcId dcId) {
  4510. if (dcId != peer->session().mainDcId()) {
  4511. _peerStatsDcIds[peer] = dcId;
  4512. }
  4513. }
  4514. void Session::saveViewAsMessages(
  4515. not_null<Forum*> forum,
  4516. bool viewAsMessages) {
  4517. const auto channel = forum->channel();
  4518. if (const auto requestId = _viewAsMessagesRequests.take(channel)) {
  4519. _session->api().request(*requestId).cancel();
  4520. }
  4521. _viewAsMessagesRequests[channel] = _session->api().request(
  4522. MTPchannels_ToggleViewForumAsMessages(
  4523. channel->inputChannel,
  4524. MTP_bool(viewAsMessages))
  4525. ).done([=] {
  4526. _viewAsMessagesRequests.remove(channel);
  4527. }).fail([=] {
  4528. _viewAsMessagesRequests.remove(channel);
  4529. }).send();
  4530. channel->setViewAsMessagesFlag(viewAsMessages);
  4531. }
  4532. void Session::webViewResultSent(WebViewResultSent &&sent) {
  4533. return _webViewResultSent.fire(std::move(sent));
  4534. }
  4535. auto Session::webViewResultSent() const -> rpl::producer<WebViewResultSent> {
  4536. return _webViewResultSent.events();
  4537. }
  4538. rpl::producer<not_null<PeerData*>> Session::peerDecorationsUpdated() const {
  4539. return _peerDecorationsUpdated.events();
  4540. }
  4541. void Session::viewTagsChanged(
  4542. not_null<ViewElement*> view,
  4543. std::vector<Data::ReactionId> &&was,
  4544. std::vector<Data::ReactionId> &&now) {
  4545. for (const auto &id : now) {
  4546. const auto i = ranges::remove(was, id);
  4547. if (i != end(was)) {
  4548. was.erase(i, end(was));
  4549. } else {
  4550. _viewsByTag[id].emplace(view);
  4551. }
  4552. }
  4553. for (const auto &id : was) {
  4554. const auto i = _viewsByTag.find(id);
  4555. if (i != end(_viewsByTag)
  4556. && i->second.remove(view)
  4557. && i->second.empty()) {
  4558. _viewsByTag.erase(i);
  4559. }
  4560. }
  4561. }
  4562. void Session::sentToScheduled(SentToScheduled value) {
  4563. _sentToScheduled.fire(std::move(value));
  4564. }
  4565. rpl::producer<SentToScheduled> Session::sentToScheduled() const {
  4566. return _sentToScheduled.events();
  4567. }
  4568. void Session::sentFromScheduled(SentFromScheduled value) {
  4569. _sentFromScheduled.fire(std::move(value));
  4570. }
  4571. rpl::producer<SentFromScheduled> Session::sentFromScheduled() const {
  4572. return _sentFromScheduled.events();
  4573. }
  4574. void Session::clearLocalStorage() {
  4575. _cache->close();
  4576. _cache->clear();
  4577. _bigFileCache->close();
  4578. _bigFileCache->clear();
  4579. }
  4580. } // namespace Data