apiwrap.cpp 137 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769
  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 "apiwrap.h"
  8. #include "api/api_authorizations.h"
  9. #include "api/api_attached_stickers.h"
  10. #include "api/api_blocked_peers.h"
  11. #include "api/api_chat_links.h"
  12. #include "api/api_chat_participants.h"
  13. #include "api/api_cloud_password.h"
  14. #include "api/api_hash.h"
  15. #include "api/api_invite_links.h"
  16. #include "api/api_media.h"
  17. #include "api/api_peer_colors.h"
  18. #include "api/api_peer_photo.h"
  19. #include "api/api_polls.h"
  20. #include "api/api_sending.h"
  21. #include "api/api_text_entities.h"
  22. #include "api/api_self_destruct.h"
  23. #include "api/api_sensitive_content.h"
  24. #include "api/api_global_privacy.h"
  25. #include "api/api_updates.h"
  26. #include "api/api_user_privacy.h"
  27. #include "api/api_views.h"
  28. #include "api/api_confirm_phone.h"
  29. #include "api/api_unread_things.h"
  30. #include "api/api_ringtones.h"
  31. #include "api/api_transcribes.h"
  32. #include "api/api_premium.h"
  33. #include "api/api_user_names.h"
  34. #include "api/api_websites.h"
  35. #include "data/business/data_shortcut_messages.h"
  36. #include "data/components/scheduled_messages.h"
  37. #include "data/notify/data_notify_settings.h"
  38. #include "data/data_changes.h"
  39. #include "data/data_web_page.h"
  40. #include "data/data_folder.h"
  41. #include "data/data_forum_topic.h"
  42. #include "data/data_forum.h"
  43. #include "data/data_saved_sublist.h"
  44. #include "data/data_search_controller.h"
  45. #include "data/data_session.h"
  46. #include "data/data_channel.h"
  47. #include "data/data_chat.h"
  48. #include "data/data_user.h"
  49. #include "data/data_chat_filters.h"
  50. #include "data/data_histories.h"
  51. #include "data/data_history_messages.h"
  52. #include "core/core_cloud_password.h"
  53. #include "core/application.h"
  54. #include "base/unixtime.h"
  55. #include "base/random.h"
  56. #include "base/call_delayed.h"
  57. #include "lang/lang_keys.h"
  58. #include "mainwidget.h"
  59. #include "boxes/add_contact_box.h"
  60. #include "mtproto/mtproto_config.h"
  61. #include "history/history.h"
  62. #include "history/history_item_components.h"
  63. #include "history/history_item_helpers.h"
  64. #include "main/main_session.h"
  65. #include "main/main_session_settings.h"
  66. #include "main/main_account.h"
  67. #include "ui/boxes/confirm_box.h"
  68. #include "boxes/sticker_set_box.h"
  69. #include "boxes/premium_limits_box.h"
  70. #include "window/notifications_manager.h"
  71. #include "window/window_controller.h"
  72. #include "window/window_lock_widgets.h"
  73. #include "window/window_session_controller.h"
  74. #include "inline_bots/inline_bot_result.h"
  75. #include "chat_helpers/message_field.h"
  76. #include "ui/item_text_options.h"
  77. #include "ui/text/text_utilities.h"
  78. #include "ui/chat/attach/attach_prepare.h"
  79. #include "ui/toast/toast.h"
  80. #include "support/support_helper.h"
  81. #include "settings/settings_premium.h"
  82. #include "storage/localimageloader.h"
  83. #include "storage/download_manager_mtproto.h"
  84. #include "storage/file_upload.h"
  85. #include "storage/storage_account.h"
  86. namespace {
  87. // Save draft to the cloud with 1 sec extra delay.
  88. constexpr auto kSaveCloudDraftTimeout = 1000;
  89. constexpr auto kTopPromotionInterval = TimeId(60 * 60);
  90. constexpr auto kTopPromotionMinDelay = TimeId(10);
  91. constexpr auto kSmallDelayMs = 5;
  92. constexpr auto kReadFeaturedSetsTimeout = crl::time(1000);
  93. constexpr auto kFileLoaderQueueStopTimeout = crl::time(5000);
  94. constexpr auto kStickersByEmojiInvalidateTimeout = crl::time(6 * 1000);
  95. constexpr auto kNotifySettingSaveTimeout = crl::time(1000);
  96. constexpr auto kDialogsFirstLoad = 20;
  97. constexpr auto kDialogsPerPage = 500;
  98. constexpr auto kStatsSessionKillTimeout = 10 * crl::time(1000);
  99. using PhotoFileLocationId = Data::PhotoFileLocationId;
  100. using DocumentFileLocationId = Data::DocumentFileLocationId;
  101. using UpdatedFileReferences = Data::UpdatedFileReferences;
  102. [[nodiscard]] TimeId UnixtimeFromMsgId(mtpMsgId msgId) {
  103. return TimeId(msgId >> 32);
  104. }
  105. [[nodiscard]] std::shared_ptr<ChatHelpers::Show> ShowForPeer(
  106. not_null<PeerData*> peer) {
  107. if (const auto window = Core::App().windowFor(peer)) {
  108. if (const auto controller = window->sessionController()) {
  109. if (&controller->session() == &peer->session()) {
  110. return controller->uiShow();
  111. }
  112. }
  113. }
  114. return nullptr;
  115. }
  116. void ShowChannelsLimitBox(not_null<PeerData*> peer) {
  117. if (const auto window = Core::App().windowFor(peer)) {
  118. window->invokeForSessionController(
  119. &peer->session().account(),
  120. peer,
  121. [&](not_null<Window::SessionController*> controller) {
  122. controller->show(Box(ChannelsLimitBox, &peer->session()));
  123. });
  124. }
  125. }
  126. [[nodiscard]] FileLoadTo FileLoadTaskOptions(const Api::SendAction &action) {
  127. const auto peer = action.history->peer;
  128. return FileLoadTo(
  129. peer->id,
  130. action.options,
  131. action.replyTo,
  132. action.replaceMediaOf);
  133. }
  134. [[nodiscard]] QString FormatVideoTimestamp(TimeId seconds) {
  135. const auto minutes = seconds / 60;
  136. const auto hours = minutes / 60;
  137. return hours
  138. ? u"%1h%2m%3s"_q.arg(hours).arg(minutes % 60).arg(seconds % 60)
  139. : minutes
  140. ? u"%1m%2s"_q.arg(minutes).arg(seconds % 60)
  141. : QString::number(seconds);
  142. }
  143. } // namespace
  144. ApiWrap::ApiWrap(not_null<Main::Session*> session)
  145. : MTP::Sender(&session->account().mtp())
  146. , _session(session)
  147. , _messageDataResolveDelayed([=] { resolveMessageDatas(); })
  148. , _webPagesTimer([=] { resolveWebPages(); })
  149. , _draftsSaveTimer([=] { saveDraftsToCloud(); })
  150. , _featuredSetsReadTimer([=] { readFeaturedSets(); })
  151. , _dialogsLoadState(std::make_unique<DialogsLoadState>())
  152. , _fileLoader(std::make_unique<TaskQueue>(kFileLoaderQueueStopTimeout))
  153. , _topPromotionTimer([=] { refreshTopPromotion(); })
  154. , _updateNotifyTimer([=] { sendNotifySettingsUpdates(); })
  155. , _statsSessionKillTimer([=] { checkStatsSessions(); })
  156. , _authorizations(std::make_unique<Api::Authorizations>(this))
  157. , _attachedStickers(std::make_unique<Api::AttachedStickers>(this))
  158. , _blockedPeers(std::make_unique<Api::BlockedPeers>(this))
  159. , _cloudPassword(std::make_unique<Api::CloudPassword>(this))
  160. , _selfDestruct(std::make_unique<Api::SelfDestruct>(this))
  161. , _sensitiveContent(std::make_unique<Api::SensitiveContent>(this))
  162. , _globalPrivacy(std::make_unique<Api::GlobalPrivacy>(this))
  163. , _userPrivacy(std::make_unique<Api::UserPrivacy>(this))
  164. , _inviteLinks(std::make_unique<Api::InviteLinks>(this))
  165. , _chatLinks(std::make_unique<Api::ChatLinks>(this))
  166. , _views(std::make_unique<Api::ViewsManager>(this))
  167. , _confirmPhone(std::make_unique<Api::ConfirmPhone>(this))
  168. , _peerPhoto(std::make_unique<Api::PeerPhoto>(this))
  169. , _polls(std::make_unique<Api::Polls>(this))
  170. , _chatParticipants(std::make_unique<Api::ChatParticipants>(this))
  171. , _unreadThings(std::make_unique<Api::UnreadThings>(this))
  172. , _ringtones(std::make_unique<Api::Ringtones>(this))
  173. , _transcribes(std::make_unique<Api::Transcribes>(this))
  174. , _premium(std::make_unique<Api::Premium>(this))
  175. , _usernames(std::make_unique<Api::Usernames>(this))
  176. , _websites(std::make_unique<Api::Websites>(this))
  177. , _peerColors(std::make_unique<Api::PeerColors>(this)) {
  178. crl::on_main(session, [=] {
  179. // You can't use _session->lifetime() in the constructor,
  180. // only queued, because it is not constructed yet.
  181. _session->data().chatsFilters().changed(
  182. ) | rpl::filter([=] {
  183. return _session->data().chatsFilters().archiveNeeded();
  184. }) | rpl::start_with_next([=] {
  185. requestMoreDialogsIfNeeded();
  186. }, _session->lifetime());
  187. setupSupportMode();
  188. Core::App().settings().proxy().connectionTypeValue(
  189. ) | rpl::start_with_next([=] {
  190. refreshTopPromotion();
  191. }, _session->lifetime());
  192. });
  193. }
  194. ApiWrap::~ApiWrap() = default;
  195. Main::Session &ApiWrap::session() const {
  196. return *_session;
  197. }
  198. Storage::Account &ApiWrap::local() const {
  199. return _session->local();
  200. }
  201. Api::Updates &ApiWrap::updates() const {
  202. return _session->updates();
  203. }
  204. void ApiWrap::setupSupportMode() {
  205. if (!_session->supportMode()) {
  206. return;
  207. }
  208. _session->settings().supportChatsTimeSliceValue(
  209. ) | rpl::start_with_next([=](int seconds) {
  210. _dialogsLoadTill = seconds ? std::max(base::unixtime::now() - seconds, 0) : 0;
  211. refreshDialogsLoadBlocked();
  212. }, _session->lifetime());
  213. }
  214. void ApiWrap::requestChangelog(
  215. const QString &sinceVersion,
  216. Fn<void(const MTPUpdates &result)> callback) {
  217. //request(MTPhelp_GetAppChangelog(
  218. // MTP_string(sinceVersion)
  219. //)).done(
  220. // callback
  221. //).send();
  222. }
  223. void ApiWrap::refreshTopPromotion() {
  224. const auto now = base::unixtime::now();
  225. const auto next = (_topPromotionNextRequestTime != 0)
  226. ? _topPromotionNextRequestTime
  227. : now;
  228. if (_topPromotionRequestId) {
  229. getTopPromotionDelayed(now, next);
  230. return;
  231. }
  232. const auto key = [&]() -> std::pair<QString, uint32> {
  233. if (!Core::App().settings().proxy().isEnabled()) {
  234. return {};
  235. }
  236. const auto &proxy = Core::App().settings().proxy().selected();
  237. if (proxy.type != MTP::ProxyData::Type::Mtproto) {
  238. return {};
  239. }
  240. return { proxy.host, proxy.port };
  241. }();
  242. if (_topPromotionKey == key && now < next) {
  243. getTopPromotionDelayed(now, next);
  244. return;
  245. }
  246. _topPromotionKey = key;
  247. _topPromotionRequestId = request(MTPhelp_GetPromoData(
  248. )).done([=](const MTPhelp_PromoData &result) {
  249. _topPromotionRequestId = 0;
  250. topPromotionDone(result);
  251. }).fail([=] {
  252. _topPromotionRequestId = 0;
  253. const auto now = base::unixtime::now();
  254. const auto next = _topPromotionNextRequestTime = now
  255. + kTopPromotionInterval;
  256. if (!_topPromotionTimer.isActive()) {
  257. getTopPromotionDelayed(now, next);
  258. }
  259. }).send();
  260. }
  261. void ApiWrap::getTopPromotionDelayed(TimeId now, TimeId next) {
  262. _topPromotionTimer.callOnce(std::min(
  263. std::max(next - now, kTopPromotionMinDelay),
  264. kTopPromotionInterval) * crl::time(1000));
  265. };
  266. void ApiWrap::topPromotionDone(const MTPhelp_PromoData &proxy) {
  267. _topPromotionNextRequestTime = proxy.match([&](const auto &data) {
  268. return data.vexpires().v;
  269. });
  270. getTopPromotionDelayed(
  271. base::unixtime::now(),
  272. _topPromotionNextRequestTime);
  273. proxy.match([&](const MTPDhelp_promoDataEmpty &data) {
  274. _session->data().setTopPromoted(nullptr, QString(), QString());
  275. }, [&](const MTPDhelp_promoData &data) {
  276. _session->data().processChats(data.vchats());
  277. _session->data().processUsers(data.vusers());
  278. const auto peerId = peerFromMTP(data.vpeer());
  279. const auto history = _session->data().history(peerId);
  280. _session->data().setTopPromoted(
  281. history,
  282. data.vpsa_type().value_or_empty(),
  283. data.vpsa_message().value_or_empty());
  284. });
  285. }
  286. void ApiWrap::requestDeepLinkInfo(
  287. const QString &path,
  288. Fn<void(TextWithEntities message, bool updateRequired)> callback) {
  289. request(_deepLinkInfoRequestId).cancel();
  290. _deepLinkInfoRequestId = request(MTPhelp_GetDeepLinkInfo(
  291. MTP_string(path)
  292. )).done([=](const MTPhelp_DeepLinkInfo &result) {
  293. _deepLinkInfoRequestId = 0;
  294. if (result.type() == mtpc_help_deepLinkInfo) {
  295. const auto &data = result.c_help_deepLinkInfo();
  296. callback(TextWithEntities{
  297. qs(data.vmessage()),
  298. Api::EntitiesFromMTP(
  299. _session,
  300. data.ventities().value_or_empty())
  301. }, data.is_update_app());
  302. }
  303. }).fail([=] {
  304. _deepLinkInfoRequestId = 0;
  305. }).send();
  306. }
  307. void ApiWrap::requestTermsUpdate() {
  308. if (_termsUpdateRequestId) {
  309. return;
  310. }
  311. const auto now = crl::now();
  312. if (_termsUpdateSendAt && now < _termsUpdateSendAt) {
  313. base::call_delayed(_termsUpdateSendAt - now, _session, [=] {
  314. requestTermsUpdate();
  315. });
  316. return;
  317. }
  318. constexpr auto kTermsUpdateTimeoutMin = 10 * crl::time(1000);
  319. constexpr auto kTermsUpdateTimeoutMax = 86400 * crl::time(1000);
  320. _termsUpdateRequestId = request(MTPhelp_GetTermsOfServiceUpdate(
  321. )).done([=](const MTPhelp_TermsOfServiceUpdate &result) {
  322. _termsUpdateRequestId = 0;
  323. const auto requestNext = [&](auto &&data) {
  324. const auto timeout = (data.vexpires().v - base::unixtime::now());
  325. _termsUpdateSendAt = crl::now() + std::clamp(
  326. timeout * crl::time(1000),
  327. kTermsUpdateTimeoutMin,
  328. kTermsUpdateTimeoutMax);
  329. requestTermsUpdate();
  330. };
  331. switch (result.type()) {
  332. case mtpc_help_termsOfServiceUpdateEmpty: {
  333. const auto &data = result.c_help_termsOfServiceUpdateEmpty();
  334. requestNext(data);
  335. } break;
  336. case mtpc_help_termsOfServiceUpdate: {
  337. const auto &data = result.c_help_termsOfServiceUpdate();
  338. const auto &terms = data.vterms_of_service();
  339. const auto &fields = terms.c_help_termsOfService();
  340. session().lockByTerms(
  341. Window::TermsLock::FromMTP(_session, fields));
  342. requestNext(data);
  343. } break;
  344. default: Unexpected("Type in requestTermsUpdate().");
  345. }
  346. }).fail([=] {
  347. _termsUpdateRequestId = 0;
  348. _termsUpdateSendAt = crl::now() + kTermsUpdateTimeoutMin;
  349. requestTermsUpdate();
  350. }).send();
  351. }
  352. void ApiWrap::acceptTerms(bytes::const_span id) {
  353. request(MTPhelp_AcceptTermsOfService(
  354. MTP_dataJSON(MTP_bytes(id))
  355. )).done([=] {
  356. requestTermsUpdate();
  357. }).send();
  358. }
  359. void ApiWrap::checkChatInvite(
  360. const QString &hash,
  361. FnMut<void(const MTPChatInvite &)> done,
  362. Fn<void(const MTP::Error &)> fail) {
  363. request(base::take(_checkInviteRequestId)).cancel();
  364. _checkInviteRequestId = request(MTPmessages_CheckChatInvite(
  365. MTP_string(hash)
  366. )).done(std::move(done)).fail(std::move(fail)).send();
  367. }
  368. void ApiWrap::checkFilterInvite(
  369. const QString &slug,
  370. FnMut<void(const MTPchatlists_ChatlistInvite &)> done,
  371. Fn<void(const MTP::Error &)> fail) {
  372. request(base::take(_checkFilterInviteRequestId)).cancel();
  373. _checkFilterInviteRequestId = request(
  374. MTPchatlists_CheckChatlistInvite(MTP_string(slug))
  375. ).done(std::move(done)).fail(std::move(fail)).send();
  376. }
  377. void ApiWrap::savePinnedOrder(Data::Folder *folder) {
  378. const auto &order = _session->data().pinnedChatsOrder(folder);
  379. const auto input = [](Dialogs::Key key) {
  380. if (const auto history = key.history()) {
  381. return MTP_inputDialogPeer(history->peer->input);
  382. } else if (const auto folder = key.folder()) {
  383. return MTP_inputDialogPeerFolder(MTP_int(folder->id()));
  384. }
  385. Unexpected("Key type in pinnedDialogsOrder().");
  386. };
  387. auto peers = QVector<MTPInputDialogPeer>();
  388. peers.reserve(order.size());
  389. ranges::transform(
  390. order,
  391. ranges::back_inserter(peers),
  392. input);
  393. request(MTPmessages_ReorderPinnedDialogs(
  394. MTP_flags(MTPmessages_ReorderPinnedDialogs::Flag::f_force),
  395. MTP_int(folder ? folder->id() : 0),
  396. MTP_vector(peers)
  397. )).send();
  398. }
  399. void ApiWrap::savePinnedOrder(not_null<Data::Forum*> forum) {
  400. const auto &order = _session->data().pinnedChatsOrder(forum);
  401. const auto input = [](Dialogs::Key key) {
  402. if (const auto topic = key.topic()) {
  403. return MTP_int(topic->rootId().bare);
  404. }
  405. Unexpected("Key type in pinnedDialogsOrder().");
  406. };
  407. auto topics = QVector<MTPint>();
  408. topics.reserve(order.size());
  409. ranges::transform(
  410. order,
  411. ranges::back_inserter(topics),
  412. input);
  413. request(MTPchannels_ReorderPinnedForumTopics(
  414. MTP_flags(MTPchannels_ReorderPinnedForumTopics::Flag::f_force),
  415. forum->channel()->inputChannel,
  416. MTP_vector(topics)
  417. )).done([=](const MTPUpdates &result) {
  418. applyUpdates(result);
  419. }).send();
  420. }
  421. void ApiWrap::savePinnedOrder(not_null<Data::SavedMessages*> saved) {
  422. const auto &order = _session->data().pinnedChatsOrder(saved);
  423. const auto input = [](Dialogs::Key key) {
  424. if (const auto sublist = key.sublist()) {
  425. return MTP_inputDialogPeer(sublist->peer()->input);
  426. }
  427. Unexpected("Key type in pinnedDialogsOrder().");
  428. };
  429. auto peers = QVector<MTPInputDialogPeer>();
  430. peers.reserve(order.size());
  431. ranges::transform(
  432. order,
  433. ranges::back_inserter(peers),
  434. input);
  435. request(MTPmessages_ReorderPinnedSavedDialogs(
  436. MTP_flags(MTPmessages_ReorderPinnedSavedDialogs::Flag::f_force),
  437. MTP_vector(peers)
  438. )).send();
  439. }
  440. void ApiWrap::toggleHistoryArchived(
  441. not_null<History*> history,
  442. bool archived,
  443. Fn<void()> callback) {
  444. if (const auto already = _historyArchivedRequests.take(history)) {
  445. request(already->first).cancel();
  446. }
  447. const auto isPinned = history->isPinnedDialog(0);
  448. const auto archiveId = Data::Folder::kId;
  449. const auto requestId = request(MTPfolders_EditPeerFolders(
  450. MTP_vector<MTPInputFolderPeer>(
  451. 1,
  452. MTP_inputFolderPeer(
  453. history->peer->input,
  454. MTP_int(archived ? archiveId : 0)))
  455. )).done([=](const MTPUpdates &result) {
  456. applyUpdates(result);
  457. if (archived) {
  458. history->setFolder(_session->data().folder(archiveId));
  459. } else {
  460. history->clearFolder();
  461. }
  462. if (const auto data = _historyArchivedRequests.take(history)) {
  463. data->second();
  464. }
  465. if (isPinned) {
  466. _session->data().notifyPinnedDialogsOrderUpdated();
  467. }
  468. }).fail([=] {
  469. _historyArchivedRequests.remove(history);
  470. }).send();
  471. _historyArchivedRequests.emplace(history, requestId, callback);
  472. }
  473. void ApiWrap::sendMessageFail(
  474. const MTP::Error &error,
  475. not_null<PeerData*> peer,
  476. uint64 randomId,
  477. FullMsgId itemId) {
  478. sendMessageFail(error.type(), peer, randomId, itemId);
  479. }
  480. void ApiWrap::sendMessageFail(
  481. const QString &error,
  482. not_null<PeerData*> peer,
  483. uint64 randomId,
  484. FullMsgId itemId) {
  485. const auto show = ShowForPeer(peer);
  486. const auto paidStarsPrefix = u"ALLOW_PAYMENT_REQUIRED_"_q;
  487. if (show && error == u"PEER_FLOOD"_q) {
  488. show->showBox(
  489. Ui::MakeInformBox(
  490. PeerFloodErrorText(&session(), PeerFloodType::Send)),
  491. Ui::LayerOption::CloseOther);
  492. } else if (show && error == u"USER_BANNED_IN_CHANNEL"_q) {
  493. const auto link = Ui::Text::Link(
  494. tr::lng_cant_more_info(tr::now),
  495. session().createInternalLinkFull(u"spambot"_q));
  496. show->showBox(
  497. Ui::MakeInformBox(
  498. tr::lng_error_public_groups_denied(
  499. tr::now,
  500. lt_more_info,
  501. link,
  502. Ui::Text::WithEntities)),
  503. Ui::LayerOption::CloseOther);
  504. } else if (error.startsWith(u"SLOWMODE_WAIT_"_q)) {
  505. const auto chop = u"SLOWMODE_WAIT_"_q.size();
  506. const auto left = base::StringViewMid(error, chop).toInt();
  507. if (const auto channel = peer->asChannel()) {
  508. const auto seconds = channel->slowmodeSeconds();
  509. if (seconds >= left) {
  510. channel->growSlowmodeLastMessage(
  511. base::unixtime::now() - (left - seconds));
  512. } else {
  513. requestFullPeer(peer);
  514. }
  515. }
  516. } else if (error == u"SCHEDULE_STATUS_PRIVATE"_q) {
  517. auto &scheduled = _session->scheduledMessages();
  518. Assert(peer->isUser());
  519. if (const auto item = scheduled.lookupItem(peer->id, itemId.msg)) {
  520. scheduled.removeSending(item);
  521. if (show) {
  522. show->showBox(
  523. Ui::MakeInformBox(tr::lng_cant_do_this()),
  524. Ui::LayerOption::CloseOther);
  525. }
  526. }
  527. } else if (show && error == u"CHAT_FORWARDS_RESTRICTED"_q) {
  528. show->showToast(peer->isBroadcast()
  529. ? tr::lng_error_noforwards_channel(tr::now)
  530. : tr::lng_error_noforwards_group(tr::now), kJoinErrorDuration);
  531. } else if (error == u"PREMIUM_ACCOUNT_REQUIRED"_q) {
  532. Settings::ShowPremium(&session(), "premium_stickers");
  533. } else if (error == u"SCHEDULE_TOO_MUCH"_q) {
  534. auto &scheduled = _session->scheduledMessages();
  535. if (const auto item = scheduled.lookupItem(peer->id, itemId.msg)) {
  536. scheduled.removeSending(item);
  537. }
  538. if (show) {
  539. show->showToast(tr::lng_error_schedule_limit(tr::now));
  540. }
  541. } else if (error.startsWith(paidStarsPrefix)) {
  542. if (show) {
  543. show->showToast(
  544. u"Payment requirements changed. Please, try again."_q);
  545. }
  546. if (const auto stars = error.mid(paidStarsPrefix.size()).toInt()) {
  547. if (const auto user = peer->asUser()) {
  548. user->setStarsPerMessage(stars);
  549. } else if (const auto channel = peer->asChannel()) {
  550. channel->setStarsPerMessage(stars);
  551. }
  552. }
  553. peer->updateFull();
  554. }
  555. if (const auto item = _session->data().message(itemId)) {
  556. Assert(randomId != 0);
  557. _session->data().unregisterMessageRandomId(randomId);
  558. item->sendFailed();
  559. if (error == u"TOPIC_CLOSED"_q) {
  560. if (const auto topic = item->topic()) {
  561. topic->setClosed(true);
  562. }
  563. }
  564. }
  565. }
  566. void ApiWrap::requestMessageData(
  567. PeerData *peer,
  568. MsgId msgId,
  569. Fn<void()> done) {
  570. auto &requests = (peer && peer->isChannel())
  571. ? _channelMessageDataRequests[peer->asChannel()][msgId]
  572. : _messageDataRequests[msgId];
  573. if (done) {
  574. requests.callbacks.push_back(std::move(done));
  575. }
  576. if (!requests.requestId) {
  577. _messageDataResolveDelayed.call();
  578. }
  579. }
  580. QVector<MTPInputMessage> ApiWrap::collectMessageIds(
  581. const MessageDataRequests &requests) {
  582. auto result = QVector<MTPInputMessage>();
  583. result.reserve(requests.size());
  584. for (const auto &[msgId, request] : requests) {
  585. if (request.requestId > 0) {
  586. continue;
  587. }
  588. result.push_back(MTP_inputMessageID(MTP_int(msgId)));
  589. }
  590. return result;
  591. }
  592. auto ApiWrap::messageDataRequests(ChannelData *channel, bool onlyExisting)
  593. -> MessageDataRequests* {
  594. if (!channel) {
  595. return &_messageDataRequests;
  596. }
  597. const auto i = _channelMessageDataRequests.find(channel);
  598. if (i != end(_channelMessageDataRequests)) {
  599. return &i->second;
  600. } else if (onlyExisting) {
  601. return nullptr;
  602. }
  603. return &_channelMessageDataRequests.emplace(
  604. channel,
  605. MessageDataRequests()
  606. ).first->second;
  607. }
  608. void ApiWrap::resolveMessageDatas() {
  609. if (_messageDataRequests.empty() && _channelMessageDataRequests.empty()) {
  610. return;
  611. }
  612. const auto ids = collectMessageIds(_messageDataRequests);
  613. if (!ids.isEmpty()) {
  614. const auto requestId = request(MTPmessages_GetMessages(
  615. MTP_vector<MTPInputMessage>(ids)
  616. )).done([=](
  617. const MTPmessages_Messages &result,
  618. mtpRequestId requestId) {
  619. _session->data().processExistingMessages(nullptr, result);
  620. finalizeMessageDataRequest(nullptr, requestId);
  621. }).fail([=](const MTP::Error &error, mtpRequestId requestId) {
  622. finalizeMessageDataRequest(nullptr, requestId);
  623. }).afterDelay(kSmallDelayMs).send();
  624. for (auto &[msgId, request] : _messageDataRequests) {
  625. if (request.requestId > 0) {
  626. continue;
  627. }
  628. request.requestId = requestId;
  629. }
  630. }
  631. for (auto j = _channelMessageDataRequests.begin(); j != _channelMessageDataRequests.cend();) {
  632. if (j->second.empty()) {
  633. j = _channelMessageDataRequests.erase(j);
  634. continue;
  635. }
  636. const auto ids = collectMessageIds(j->second);
  637. if (!ids.isEmpty()) {
  638. const auto channel = j->first;
  639. const auto requestId = request(MTPchannels_GetMessages(
  640. channel->inputChannel,
  641. MTP_vector<MTPInputMessage>(ids)
  642. )).done([=](
  643. const MTPmessages_Messages &result,
  644. mtpRequestId requestId) {
  645. _session->data().processExistingMessages(channel, result);
  646. finalizeMessageDataRequest(channel, requestId);
  647. }).fail([=](const MTP::Error &error, mtpRequestId requestId) {
  648. finalizeMessageDataRequest(channel, requestId);
  649. }).afterDelay(kSmallDelayMs).send();
  650. for (auto &[msgId, request] : j->second) {
  651. if (request.requestId > 0) {
  652. continue;
  653. }
  654. request.requestId = requestId;
  655. }
  656. }
  657. ++j;
  658. }
  659. }
  660. void ApiWrap::finalizeMessageDataRequest(
  661. ChannelData *channel,
  662. mtpRequestId requestId) {
  663. auto requests = messageDataRequests(channel, true);
  664. if (!requests) {
  665. return;
  666. }
  667. auto callbacks = std::vector<Fn<void()>>();
  668. for (auto i = requests->begin(); i != requests->cend();) {
  669. if (i->second.requestId == requestId) {
  670. auto &list = i->second.callbacks;
  671. if (callbacks.empty()) {
  672. callbacks = std::move(list);
  673. } else {
  674. callbacks.insert(
  675. end(callbacks),
  676. std::make_move_iterator(begin(list)),
  677. std::make_move_iterator(end(list)));
  678. }
  679. i = requests->erase(i);
  680. } else {
  681. ++i;
  682. }
  683. }
  684. if (channel && requests->empty()) {
  685. _channelMessageDataRequests.remove(channel);
  686. }
  687. for (const auto &callback : callbacks) {
  688. callback();
  689. }
  690. }
  691. QString ApiWrap::exportDirectMessageLink(
  692. not_null<HistoryItem*> item,
  693. bool inRepliesContext,
  694. bool forceNonPublicLink,
  695. std::optional<TimeId> videoTimestamp) {
  696. Expects(item->history()->peer->isChannel());
  697. const auto itemId = item->fullId();
  698. const auto channel = item->history()->peer->asChannel();
  699. const auto fallback = [&] {
  700. auto linkChannel = channel;
  701. auto linkItemId = item->id;
  702. auto linkCommentId = MsgId();
  703. auto linkThreadId = MsgId();
  704. auto linkThreadIsTopic = false;
  705. if (inRepliesContext) {
  706. linkThreadIsTopic = item->history()->isForum();
  707. const auto rootId = linkThreadIsTopic
  708. ? item->topicRootId()
  709. : item->replyToTop();
  710. if (rootId) {
  711. const auto root = item->history()->owner().message(
  712. channel->id,
  713. rootId);
  714. const auto sender = root
  715. ? root->discussionPostOriginalSender()
  716. : nullptr;
  717. if (sender && sender->hasUsername() && !forceNonPublicLink) {
  718. // Comment to a public channel.
  719. const auto forwarded = root->Get<HistoryMessageForwarded>();
  720. linkItemId = forwarded->savedFromMsgId;
  721. if (linkItemId) {
  722. linkChannel = sender;
  723. linkCommentId = item->id;
  724. } else {
  725. linkItemId = item->id;
  726. }
  727. } else {
  728. // Reply in a thread, maybe comment in a private channel.
  729. linkThreadId = rootId;
  730. }
  731. }
  732. }
  733. const auto base = (linkChannel->hasUsername() && !forceNonPublicLink)
  734. ? linkChannel->username()
  735. : "c/" + QString::number(peerToChannel(linkChannel->id).bare);
  736. const auto post = QString::number(linkItemId.bare);
  737. const auto query = base
  738. + '/'
  739. + (linkCommentId
  740. ? (post + "?comment=" + QString::number(linkCommentId.bare))
  741. : (linkThreadId && !linkThreadIsTopic)
  742. ? (post + "?thread=" + QString::number(linkThreadId.bare))
  743. : linkThreadId
  744. ? (QString::number(linkThreadId.bare) + '/' + post)
  745. : post);
  746. return session().createInternalLinkFull(query);
  747. };
  748. if (forceNonPublicLink) {
  749. return fallback();
  750. }
  751. const auto i = _unlikelyMessageLinks.find(itemId);
  752. const auto current = (i != end(_unlikelyMessageLinks))
  753. ? i->second
  754. : fallback();
  755. request(MTPchannels_ExportMessageLink(
  756. MTP_flags(inRepliesContext
  757. ? MTPchannels_ExportMessageLink::Flag::f_thread
  758. : MTPchannels_ExportMessageLink::Flag(0)),
  759. channel->inputChannel,
  760. MTP_int(item->id)
  761. )).done([=](const MTPExportedMessageLink &result) {
  762. const auto link = qs(result.data().vlink());
  763. if (current != link) {
  764. _unlikelyMessageLinks.emplace_or_assign(itemId, link);
  765. }
  766. }).send();
  767. const auto addTimestamp = channel->hasUsername()
  768. && !inRepliesContext
  769. && videoTimestamp.has_value();
  770. const auto addedSeparator = (current.indexOf('?') >= 0) ? '&' : '?';
  771. const auto addedTimestamp = addTimestamp
  772. ? (addedSeparator + u"t="_q + FormatVideoTimestamp(*videoTimestamp))
  773. : QString();
  774. return current + addedTimestamp;
  775. }
  776. QString ApiWrap::exportDirectStoryLink(not_null<Data::Story*> story) {
  777. const auto storyId = story->fullId();
  778. const auto peer = story->peer();
  779. const auto fallback = [&] {
  780. const auto base = peer->username();
  781. const auto story = QString::number(storyId.story);
  782. const auto query = base + "/s/" + story;
  783. return session().createInternalLinkFull(query);
  784. };
  785. const auto i = _unlikelyStoryLinks.find(storyId);
  786. const auto current = (i != end(_unlikelyStoryLinks))
  787. ? i->second
  788. : fallback();
  789. request(MTPstories_ExportStoryLink(
  790. peer->input,
  791. MTP_int(story->id())
  792. )).done([=](const MTPExportedStoryLink &result) {
  793. const auto link = qs(result.data().vlink());
  794. if (current != link) {
  795. _unlikelyStoryLinks.emplace_or_assign(storyId, link);
  796. }
  797. }).send();
  798. return current;
  799. }
  800. void ApiWrap::requestContacts() {
  801. if (_session->data().contactsLoaded().current() || _contactsRequestId) {
  802. return;
  803. }
  804. _contactsRequestId = request(MTPcontacts_GetContacts(
  805. MTP_long(0) // hash
  806. )).done([=](const MTPcontacts_Contacts &result) {
  807. _contactsRequestId = 0;
  808. if (result.type() == mtpc_contacts_contactsNotModified) {
  809. return;
  810. }
  811. Assert(result.type() == mtpc_contacts_contacts);
  812. const auto &d = result.c_contacts_contacts();
  813. _session->data().processUsers(d.vusers());
  814. for (const auto &contact : d.vcontacts().v) {
  815. if (contact.type() != mtpc_contact) continue;
  816. const auto userId = UserId(contact.c_contact().vuser_id());
  817. if (userId == _session->userId()) {
  818. _session->user()->setIsContact(true);
  819. }
  820. }
  821. _session->data().contactsLoaded() = true;
  822. }).fail([=] {
  823. _contactsRequestId = 0;
  824. }).send();
  825. }
  826. void ApiWrap::requestDialogs(Data::Folder *folder) {
  827. if (folder && !_foldersLoadState.contains(folder)) {
  828. _foldersLoadState.emplace(folder, DialogsLoadState());
  829. }
  830. requestMoreDialogs(folder);
  831. }
  832. void ApiWrap::requestMoreDialogs(Data::Folder *folder) {
  833. const auto state = dialogsLoadState(folder);
  834. if (!state) {
  835. return;
  836. } else if (state->requestId) {
  837. return;
  838. } else if (_dialogsLoadBlockedByDate.current()) {
  839. return;
  840. }
  841. const auto firstLoad = !state->offsetDate;
  842. const auto loadCount = firstLoad ? kDialogsFirstLoad : kDialogsPerPage;
  843. const auto flags = MTPmessages_GetDialogs::Flag::f_exclude_pinned
  844. | MTPmessages_GetDialogs::Flag::f_folder_id;
  845. const auto hash = uint64(0);
  846. state->requestId = request(MTPmessages_GetDialogs(
  847. MTP_flags(flags),
  848. MTP_int(folder ? folder->id() : 0),
  849. MTP_int(state->offsetDate),
  850. MTP_int(state->offsetId),
  851. (state->offsetPeer
  852. ? state->offsetPeer->input
  853. : MTP_inputPeerEmpty()),
  854. MTP_int(loadCount),
  855. MTP_long(hash)
  856. )).done([=](const MTPmessages_Dialogs &result) {
  857. const auto state = dialogsLoadState(folder);
  858. const auto count = result.match([](
  859. const MTPDmessages_dialogsNotModified &) {
  860. LOG(("API Error: not-modified received for requested dialogs."));
  861. return 0;
  862. }, [&](const MTPDmessages_dialogs &data) {
  863. if (state) {
  864. state->listReceived = true;
  865. dialogsLoadFinish(folder); // may kill 'state'.
  866. }
  867. return int(data.vdialogs().v.size());
  868. }, [&](const MTPDmessages_dialogsSlice &data) {
  869. updateDialogsOffset(
  870. folder,
  871. data.vdialogs().v,
  872. data.vmessages().v);
  873. return data.vcount().v;
  874. });
  875. result.match([](const MTPDmessages_dialogsNotModified & data) {
  876. LOG(("API Error: not-modified received for requested dialogs."));
  877. }, [&](const auto &data) {
  878. _session->data().processUsers(data.vusers());
  879. _session->data().processChats(data.vchats());
  880. _session->data().applyDialogs(
  881. folder,
  882. data.vmessages().v,
  883. data.vdialogs().v,
  884. count);
  885. });
  886. if (!folder
  887. && (!_dialogsLoadState || !_dialogsLoadState->listReceived)) {
  888. refreshDialogsLoadBlocked();
  889. }
  890. requestMoreDialogsIfNeeded();
  891. _session->data().chatsListChanged(folder);
  892. }).fail([=] {
  893. dialogsLoadState(folder)->requestId = 0;
  894. }).send();
  895. if (!state->pinnedReceived) {
  896. requestPinnedDialogs(folder);
  897. }
  898. if (!folder) {
  899. refreshDialogsLoadBlocked();
  900. }
  901. }
  902. void ApiWrap::refreshDialogsLoadBlocked() {
  903. _dialogsLoadMayBlockByDate = _dialogsLoadState
  904. && !_dialogsLoadState->listReceived
  905. && (_dialogsLoadTill > 0);
  906. _dialogsLoadBlockedByDate = _dialogsLoadState
  907. && !_dialogsLoadState->listReceived
  908. && !_dialogsLoadState->requestId
  909. && (_dialogsLoadTill > 0)
  910. && (_dialogsLoadState->offsetDate > 0)
  911. && (_dialogsLoadState->offsetDate <= _dialogsLoadTill);
  912. }
  913. void ApiWrap::requestMoreDialogsIfNeeded() {
  914. const auto dialogsReady = !_dialogsLoadState
  915. || _dialogsLoadState->listReceived;
  916. if (_session->data().chatsFilters().loadNextExceptions(dialogsReady)) {
  917. return;
  918. } else if (_dialogsLoadState && !_dialogsLoadState->listReceived) {
  919. if (_dialogsLoadState->requestId) {
  920. return;
  921. }
  922. requestDialogs(nullptr);
  923. } else if (const auto folder = _session->data().folderLoaded(
  924. Data::Folder::kId)) {
  925. if (_session->data().chatsFilters().archiveNeeded()) {
  926. requestMoreDialogs(folder);
  927. }
  928. }
  929. requestContacts();
  930. _session->data().shortcutMessages().preloadShortcuts();
  931. }
  932. void ApiWrap::updateDialogsOffset(
  933. Data::Folder *folder,
  934. const QVector<MTPDialog> &dialogs,
  935. const QVector<MTPMessage> &messages) {
  936. auto lastDate = TimeId(0);
  937. auto lastPeer = PeerId(0);
  938. auto lastMsgId = MsgId(0);
  939. for (const auto &dialog : ranges::views::reverse(dialogs)) {
  940. dialog.match([&](const auto &dialog) {
  941. const auto peer = peerFromMTP(dialog.vpeer());
  942. const auto messageId = dialog.vtop_message().v;
  943. if (!peer || !messageId) {
  944. return;
  945. }
  946. if (!lastPeer) {
  947. lastPeer = peer;
  948. }
  949. if (!lastMsgId) {
  950. lastMsgId = messageId;
  951. }
  952. for (const auto &message : ranges::views::reverse(messages)) {
  953. if (IdFromMessage(message) == messageId
  954. && PeerFromMessage(message) == peer) {
  955. if (const auto date = DateFromMessage(message)) {
  956. lastDate = date;
  957. }
  958. return;
  959. }
  960. }
  961. });
  962. if (lastDate) {
  963. break;
  964. }
  965. }
  966. if (const auto state = dialogsLoadState(folder)) {
  967. if (lastDate) {
  968. state->offsetDate = lastDate;
  969. state->offsetId = lastMsgId;
  970. state->offsetPeer = _session->data().peer(lastPeer);
  971. state->requestId = 0;
  972. } else {
  973. state->listReceived = true;
  974. dialogsLoadFinish(folder);
  975. }
  976. }
  977. }
  978. auto ApiWrap::dialogsLoadState(Data::Folder *folder) -> DialogsLoadState* {
  979. if (!folder) {
  980. return _dialogsLoadState.get();
  981. }
  982. const auto i = _foldersLoadState.find(folder);
  983. return (i != end(_foldersLoadState)) ? &i->second : nullptr;
  984. }
  985. void ApiWrap::dialogsLoadFinish(Data::Folder *folder) {
  986. const auto notify = [&] {
  987. Core::App().postponeCall(crl::guard(_session, [=] {
  988. _session->data().chatsListDone(folder);
  989. }));
  990. };
  991. const auto state = dialogsLoadState(folder);
  992. if (!state || !state->listReceived || !state->pinnedReceived) {
  993. return;
  994. }
  995. if (folder) {
  996. _foldersLoadState.remove(folder);
  997. notify();
  998. } else {
  999. _dialogsLoadState = nullptr;
  1000. notify();
  1001. }
  1002. }
  1003. void ApiWrap::requestPinnedDialogs(Data::Folder *folder) {
  1004. const auto state = dialogsLoadState(folder);
  1005. if (!state || state->pinnedReceived || state->pinnedRequestId) {
  1006. return;
  1007. }
  1008. const auto finalize = [=] {
  1009. if (const auto state = dialogsLoadState(folder)) {
  1010. state->pinnedRequestId = 0;
  1011. state->pinnedReceived = true;
  1012. dialogsLoadFinish(folder);
  1013. }
  1014. };
  1015. state->pinnedRequestId = request(MTPmessages_GetPinnedDialogs(
  1016. MTP_int(folder ? folder->id() : 0)
  1017. )).done([=](const MTPmessages_PeerDialogs &result) {
  1018. finalize();
  1019. result.match([&](const MTPDmessages_peerDialogs &data) {
  1020. _session->data().processUsers(data.vusers());
  1021. _session->data().processChats(data.vchats());
  1022. _session->data().clearPinnedChats(folder);
  1023. _session->data().applyDialogs(
  1024. folder,
  1025. data.vmessages().v,
  1026. data.vdialogs().v);
  1027. _session->data().chatsListChanged(folder);
  1028. _session->data().notifyPinnedDialogsOrderUpdated();
  1029. });
  1030. }).fail([=] {
  1031. finalize();
  1032. }).send();
  1033. }
  1034. void ApiWrap::requestMoreBlockedByDateDialogs() {
  1035. if (!_dialogsLoadState) {
  1036. return;
  1037. }
  1038. const auto max = _session->settings().supportChatsTimeSlice();
  1039. _dialogsLoadTill = _dialogsLoadState->offsetDate
  1040. ? (_dialogsLoadState->offsetDate - max)
  1041. : (base::unixtime::now() - max);
  1042. refreshDialogsLoadBlocked();
  1043. requestDialogs();
  1044. }
  1045. rpl::producer<bool> ApiWrap::dialogsLoadMayBlockByDate() const {
  1046. return _dialogsLoadMayBlockByDate.value();
  1047. }
  1048. rpl::producer<bool> ApiWrap::dialogsLoadBlockedByDate() const {
  1049. return _dialogsLoadBlockedByDate.value();
  1050. }
  1051. void ApiWrap::requestWallPaper(
  1052. const QString &slug,
  1053. Fn<void(const Data::WallPaper &)> done,
  1054. Fn<void()> fail) {
  1055. if (_wallPaperSlug != slug) {
  1056. _wallPaperSlug = slug;
  1057. if (_wallPaperRequestId) {
  1058. request(base::take(_wallPaperRequestId)).cancel();
  1059. }
  1060. }
  1061. _wallPaperDone = std::move(done);
  1062. _wallPaperFail = std::move(fail);
  1063. if (_wallPaperRequestId) {
  1064. return;
  1065. }
  1066. _wallPaperRequestId = request(MTPaccount_GetWallPaper(
  1067. MTP_inputWallPaperSlug(MTP_string(slug))
  1068. )).done([=](const MTPWallPaper &result) {
  1069. _wallPaperRequestId = 0;
  1070. _wallPaperSlug = QString();
  1071. if (const auto paper = Data::WallPaper::Create(_session, result)) {
  1072. if (const auto done = base::take(_wallPaperDone)) {
  1073. done(*paper);
  1074. }
  1075. } else if (const auto fail = base::take(_wallPaperFail)) {
  1076. fail();
  1077. }
  1078. }).fail([=](const MTP::Error &error) {
  1079. _wallPaperRequestId = 0;
  1080. _wallPaperSlug = QString();
  1081. if (const auto fail = base::take(_wallPaperFail)) {
  1082. fail();
  1083. }
  1084. }).send();
  1085. }
  1086. void ApiWrap::requestFullPeer(not_null<PeerData*> peer) {
  1087. if (_fullPeerRequests.contains(peer)) {
  1088. return;
  1089. }
  1090. const auto requestId = [&] {
  1091. const auto failHandler = [=](const MTP::Error &error) {
  1092. _fullPeerRequests.remove(peer);
  1093. migrateFail(peer, error.type());
  1094. };
  1095. if (const auto user = peer->asUser()) {
  1096. if (_session->supportMode()) {
  1097. _session->supportHelper().refreshInfo(user);
  1098. }
  1099. return request(MTPusers_GetFullUser(
  1100. user->inputUser
  1101. )).done([=](const MTPusers_UserFull &result) {
  1102. result.match([&](const MTPDusers_userFull &data) {
  1103. _session->data().processUsers(data.vusers());
  1104. _session->data().processChats(data.vchats());
  1105. });
  1106. gotUserFull(user, result);
  1107. }).fail(failHandler).send();
  1108. } else if (const auto chat = peer->asChat()) {
  1109. return request(MTPmessages_GetFullChat(
  1110. chat->inputChat
  1111. )).done([=](const MTPmessages_ChatFull &result) {
  1112. gotChatFull(peer, result);
  1113. }).fail(failHandler).send();
  1114. } else if (const auto channel = peer->asChannel()) {
  1115. return request(MTPchannels_GetFullChannel(
  1116. channel->inputChannel
  1117. )).done([=](const MTPmessages_ChatFull &result) {
  1118. gotChatFull(peer, result);
  1119. migrateDone(channel, channel);
  1120. }).fail(failHandler).send();
  1121. }
  1122. Unexpected("Peer type in requestFullPeer.");
  1123. }();
  1124. _fullPeerRequests.emplace(peer, requestId);
  1125. }
  1126. void ApiWrap::processFullPeer(
  1127. not_null<PeerData*> peer,
  1128. const MTPmessages_ChatFull &result) {
  1129. gotChatFull(peer, result);
  1130. }
  1131. void ApiWrap::gotChatFull(
  1132. not_null<PeerData*> peer,
  1133. const MTPmessages_ChatFull &result) {
  1134. const auto &d = result.c_messages_chatFull();
  1135. _session->data().applyMaximumChatVersions(d.vchats());
  1136. _session->data().processUsers(d.vusers());
  1137. _session->data().processChats(d.vchats());
  1138. d.vfull_chat().match([&](const MTPDchatFull &data) {
  1139. if (const auto chat = peer->asChat()) {
  1140. Data::ApplyChatUpdate(chat, data);
  1141. } else {
  1142. LOG(("MTP Error: bad type in gotChatFull for channel: %1"
  1143. ).arg(d.vfull_chat().type()));
  1144. }
  1145. }, [&](const MTPDchannelFull &data) {
  1146. if (const auto channel = peer->asChannel()) {
  1147. Data::ApplyChannelUpdate(channel, data);
  1148. } else {
  1149. LOG(("MTP Error: bad type in gotChatFull for chat: %1"
  1150. ).arg(d.vfull_chat().type()));
  1151. }
  1152. });
  1153. _fullPeerRequests.remove(peer);
  1154. _session->changes().peerUpdated(
  1155. peer,
  1156. Data::PeerUpdate::Flag::FullInfo);
  1157. }
  1158. void ApiWrap::gotUserFull(
  1159. not_null<UserData*> user,
  1160. const MTPusers_UserFull &result) {
  1161. result.match([&](const MTPDusers_userFull &data) {
  1162. data.vfull_user().match([&](const MTPDuserFull &fields) {
  1163. if (user == _session->user() && !_session->validateSelf(fields.vid().v)) {
  1164. constexpr auto kRequestUserAgainTimeout = crl::time(10000);
  1165. base::call_delayed(kRequestUserAgainTimeout, _session, [=] {
  1166. requestFullPeer(user);
  1167. });
  1168. return;
  1169. }
  1170. Data::ApplyUserUpdate(user, fields);
  1171. });
  1172. });
  1173. _fullPeerRequests.remove(user);
  1174. _session->changes().peerUpdated(
  1175. user,
  1176. Data::PeerUpdate::Flag::FullInfo);
  1177. }
  1178. void ApiWrap::requestPeerSettings(not_null<PeerData*> peer) {
  1179. if (!_requestedPeerSettings.emplace(peer).second) {
  1180. return;
  1181. }
  1182. request(MTPmessages_GetPeerSettings(
  1183. peer->input
  1184. )).done([=](const MTPmessages_PeerSettings &result) {
  1185. result.match([&](const MTPDmessages_peerSettings &data) {
  1186. _session->data().processUsers(data.vusers());
  1187. _session->data().processChats(data.vchats());
  1188. peer->setBarSettings(data.vsettings());
  1189. _requestedPeerSettings.erase(peer);
  1190. });
  1191. }).fail([=] {
  1192. _requestedPeerSettings.erase(peer);
  1193. }).send();
  1194. }
  1195. void ApiWrap::migrateChat(
  1196. not_null<ChatData*> chat,
  1197. FnMut<void(not_null<ChannelData*>)> done,
  1198. Fn<void(const QString &)> fail) {
  1199. const auto callback = [&] {
  1200. return MigrateCallbacks{ std::move(done), std::move(fail) };
  1201. };
  1202. const auto i = _migrateCallbacks.find(chat);
  1203. if (i != _migrateCallbacks.end()) {
  1204. i->second.push_back(callback());
  1205. return;
  1206. }
  1207. _migrateCallbacks.emplace(chat).first->second.push_back(callback());
  1208. if (const auto channel = chat->migrateTo()) {
  1209. session().changes().peerUpdated(
  1210. chat,
  1211. Data::PeerUpdate::Flag::Migration);
  1212. crl::on_main([=] {
  1213. migrateDone(chat, channel);
  1214. });
  1215. } else if (chat->isDeactivated()) {
  1216. crl::on_main([=] {
  1217. migrateFail(
  1218. chat,
  1219. MTP::Error::Local(
  1220. "BAD_MIGRATION",
  1221. "Chat is already deactivated").type());
  1222. });
  1223. return;
  1224. } else if (!chat->amCreator()) {
  1225. crl::on_main([=] {
  1226. migrateFail(
  1227. chat,
  1228. MTP::Error::Local(
  1229. "BAD_MIGRATION",
  1230. "Current user is not the creator of that chat").type());
  1231. });
  1232. return;
  1233. }
  1234. request(MTPmessages_MigrateChat(
  1235. chat->inputChat
  1236. )).done([=](const MTPUpdates &result) {
  1237. applyUpdates(result);
  1238. session().changes().sendNotifications();
  1239. if (const auto channel = chat->migrateTo()) {
  1240. if (auto handlers = _migrateCallbacks.take(chat)) {
  1241. _migrateCallbacks.emplace(channel, std::move(*handlers));
  1242. }
  1243. requestFullPeer(channel);
  1244. } else {
  1245. migrateFail(
  1246. chat,
  1247. MTP::Error::Local("MIGRATION_FAIL", "No channel").type());
  1248. }
  1249. }).fail([=](const MTP::Error &error) {
  1250. migrateFail(chat, error.type());
  1251. }).send();
  1252. }
  1253. void ApiWrap::migrateDone(
  1254. not_null<PeerData*> peer,
  1255. not_null<ChannelData*> channel) {
  1256. session().changes().sendNotifications();
  1257. if (auto handlers = _migrateCallbacks.take(peer)) {
  1258. for (auto &handler : *handlers) {
  1259. if (handler.done) {
  1260. handler.done(channel);
  1261. }
  1262. }
  1263. }
  1264. }
  1265. void ApiWrap::migrateFail(not_null<PeerData*> peer, const QString &error) {
  1266. if (error == u"CHANNELS_TOO_MUCH"_q) {
  1267. ShowChannelsLimitBox(peer);
  1268. }
  1269. if (auto handlers = _migrateCallbacks.take(peer)) {
  1270. for (auto &handler : *handlers) {
  1271. if (handler.fail) {
  1272. handler.fail(error);
  1273. }
  1274. }
  1275. }
  1276. }
  1277. void ApiWrap::markContentsRead(
  1278. const base::flat_set<not_null<HistoryItem*>> &items) {
  1279. auto markedIds = QVector<MTPint>();
  1280. auto channelMarkedIds = base::flat_map<
  1281. not_null<ChannelData*>,
  1282. QVector<MTPint>>();
  1283. markedIds.reserve(items.size());
  1284. for (const auto &item : items) {
  1285. if (!item->markContentsRead(true) || !item->isRegular()) {
  1286. continue;
  1287. }
  1288. if (const auto channel = item->history()->peer->asChannel()) {
  1289. channelMarkedIds[channel].push_back(MTP_int(item->id));
  1290. } else {
  1291. markedIds.push_back(MTP_int(item->id));
  1292. }
  1293. }
  1294. if (!markedIds.isEmpty()) {
  1295. request(MTPmessages_ReadMessageContents(
  1296. MTP_vector<MTPint>(markedIds)
  1297. )).done([=](const MTPmessages_AffectedMessages &result) {
  1298. applyAffectedMessages(result);
  1299. }).send();
  1300. }
  1301. for (const auto &channelIds : channelMarkedIds) {
  1302. request(MTPchannels_ReadMessageContents(
  1303. channelIds.first->inputChannel,
  1304. MTP_vector<MTPint>(channelIds.second)
  1305. )).send();
  1306. }
  1307. }
  1308. void ApiWrap::markContentsRead(not_null<HistoryItem*> item) {
  1309. if (!item->markContentsRead(true) || !item->isRegular()) {
  1310. return;
  1311. }
  1312. const auto ids = MTP_vector<MTPint>(1, MTP_int(item->id));
  1313. if (const auto channel = item->history()->peer->asChannel()) {
  1314. request(MTPchannels_ReadMessageContents(
  1315. channel->inputChannel,
  1316. ids
  1317. )).send();
  1318. } else {
  1319. request(MTPmessages_ReadMessageContents(
  1320. ids
  1321. )).done([=](const MTPmessages_AffectedMessages &result) {
  1322. applyAffectedMessages(result);
  1323. }).send();
  1324. }
  1325. }
  1326. void ApiWrap::deleteAllFromParticipant(
  1327. not_null<ChannelData*> channel,
  1328. not_null<PeerData*> from) {
  1329. const auto history = _session->data().historyLoaded(channel);
  1330. const auto ids = history
  1331. ? history->collectMessagesFromParticipantToDelete(from)
  1332. : std::vector<MsgId>();
  1333. for (const auto &msgId : ids) {
  1334. if (const auto item = _session->data().message(channel->id, msgId)) {
  1335. item->destroy();
  1336. }
  1337. }
  1338. _session->data().sendHistoryChangeNotifications();
  1339. deleteAllFromParticipantSend(channel, from);
  1340. }
  1341. void ApiWrap::deleteAllFromParticipantSend(
  1342. not_null<ChannelData*> channel,
  1343. not_null<PeerData*> from) {
  1344. request(MTPchannels_DeleteParticipantHistory(
  1345. channel->inputChannel,
  1346. from->input
  1347. )).done([=](const MTPmessages_AffectedHistory &result) {
  1348. const auto offset = applyAffectedHistory(channel, result);
  1349. if (offset > 0) {
  1350. deleteAllFromParticipantSend(channel, from);
  1351. } else if (const auto history = _session->data().historyLoaded(channel)) {
  1352. history->requestChatListMessage();
  1353. }
  1354. }).send();
  1355. }
  1356. void ApiWrap::scheduleStickerSetRequest(uint64 setId, uint64 access) {
  1357. if (!_stickerSetRequests.contains(setId)) {
  1358. _stickerSetRequests.emplace(setId, StickerSetRequest{ access });
  1359. }
  1360. }
  1361. void ApiWrap::requestStickerSets() {
  1362. for (auto &[id, info] : _stickerSetRequests) {
  1363. if (info.id) {
  1364. continue;
  1365. }
  1366. info.id = request(MTPmessages_GetStickerSet(
  1367. MTP_inputStickerSetID(
  1368. MTP_long(id),
  1369. MTP_long(info.accessHash)),
  1370. MTP_int(0) // hash
  1371. )).done([=, setId = id](const MTPmessages_StickerSet &result) {
  1372. gotStickerSet(setId, result);
  1373. }).fail([=, setId = id] {
  1374. _stickerSetRequests.remove(setId);
  1375. }).afterDelay(kSmallDelayMs).send();
  1376. }
  1377. }
  1378. void ApiWrap::saveStickerSets(
  1379. const Data::StickersSetsOrder &localOrder,
  1380. const Data::StickersSetsOrder &localRemoved,
  1381. Data::StickersType type) {
  1382. auto &setDisenableRequests = (type == Data::StickersType::Emoji)
  1383. ? _customEmojiSetDisenableRequests
  1384. : (type == Data::StickersType::Masks)
  1385. ? _maskSetDisenableRequests
  1386. : _stickerSetDisenableRequests;
  1387. const auto reorderRequestId = [=]() -> mtpRequestId & {
  1388. return (type == Data::StickersType::Emoji)
  1389. ? _customEmojiReorderRequestId
  1390. : (type == Data::StickersType::Masks)
  1391. ? _masksReorderRequestId
  1392. : _stickersReorderRequestId;
  1393. };
  1394. for (auto requestId : base::take(setDisenableRequests)) {
  1395. request(requestId).cancel();
  1396. }
  1397. request(base::take(reorderRequestId())).cancel();
  1398. request(base::take(_stickersClearRecentRequestId)).cancel();
  1399. request(base::take(_stickersClearRecentAttachedRequestId)).cancel();
  1400. const auto stickersSaveOrder = [=] {
  1401. if (localOrder.size() < 2) {
  1402. return;
  1403. }
  1404. QVector<MTPlong> mtpOrder;
  1405. mtpOrder.reserve(localOrder.size());
  1406. for (const auto setId : std::as_const(localOrder)) {
  1407. mtpOrder.push_back(MTP_long(setId));
  1408. }
  1409. using Flag = MTPmessages_ReorderStickerSets::Flag;
  1410. const auto flags = (type == Data::StickersType::Emoji)
  1411. ? Flag::f_emojis
  1412. : (type == Data::StickersType::Masks)
  1413. ? Flag::f_masks
  1414. : Flag(0);
  1415. reorderRequestId() = request(MTPmessages_ReorderStickerSets(
  1416. MTP_flags(flags),
  1417. MTP_vector<MTPlong>(mtpOrder)
  1418. )).done([=] {
  1419. reorderRequestId() = 0;
  1420. }).fail([=] {
  1421. reorderRequestId() = 0;
  1422. if (type == Data::StickersType::Emoji) {
  1423. _session->data().stickers().setLastEmojiUpdate(0);
  1424. updateCustomEmoji();
  1425. } else if (type == Data::StickersType::Masks) {
  1426. _session->data().stickers().setLastMasksUpdate(0);
  1427. updateMasks();
  1428. } else {
  1429. _session->data().stickers().setLastUpdate(0);
  1430. updateStickers();
  1431. }
  1432. }).send();
  1433. };
  1434. const auto stickerSetDisenabled = [=](mtpRequestId requestId) {
  1435. auto &setDisenableRequests = (type == Data::StickersType::Emoji)
  1436. ? _customEmojiSetDisenableRequests
  1437. : (type == Data::StickersType::Masks)
  1438. ? _maskSetDisenableRequests
  1439. : _stickerSetDisenableRequests;
  1440. setDisenableRequests.remove(requestId);
  1441. if (setDisenableRequests.empty()) {
  1442. stickersSaveOrder();
  1443. }
  1444. };
  1445. auto writeInstalled = true,
  1446. writeRecent = false,
  1447. writeCloudRecent = false,
  1448. writeCloudRecentAttached = false,
  1449. writeFaved = false,
  1450. writeArchived = false;
  1451. auto &recent = _session->data().stickers().getRecentPack();
  1452. auto &sets = _session->data().stickers().setsRef();
  1453. auto &order = (type == Data::StickersType::Emoji)
  1454. ? _session->data().stickers().emojiSetsOrder()
  1455. : (type == Data::StickersType::Masks)
  1456. ? _session->data().stickers().maskSetsOrder()
  1457. : _session->data().stickers().setsOrder();
  1458. auto &orderRef = (type == Data::StickersType::Emoji)
  1459. ? _session->data().stickers().emojiSetsOrderRef()
  1460. : (type == Data::StickersType::Masks)
  1461. ? _session->data().stickers().maskSetsOrderRef()
  1462. : _session->data().stickers().setsOrderRef();
  1463. using Flag = Data::StickersSetFlag;
  1464. for (const auto removedSetId : localRemoved) {
  1465. if ((removedSetId == Data::Stickers::CloudRecentSetId)
  1466. || (removedSetId == Data::Stickers::CloudRecentAttachedSetId)) {
  1467. if (sets.remove(Data::Stickers::CloudRecentSetId) != 0) {
  1468. writeCloudRecent = true;
  1469. }
  1470. if (sets.remove(Data::Stickers::CloudRecentAttachedSetId) != 0) {
  1471. writeCloudRecentAttached = true;
  1472. }
  1473. if (sets.remove(Data::Stickers::CustomSetId)) {
  1474. writeInstalled = true;
  1475. }
  1476. if (!recent.isEmpty()) {
  1477. recent.clear();
  1478. writeRecent = true;
  1479. }
  1480. const auto isAttached
  1481. = (removedSetId == Data::Stickers::CloudRecentAttachedSetId);
  1482. const auto flags = isAttached
  1483. ? MTPmessages_ClearRecentStickers::Flag::f_attached
  1484. : MTPmessages_ClearRecentStickers::Flags(0);
  1485. auto &requestId = isAttached
  1486. ? _stickersClearRecentAttachedRequestId
  1487. : _stickersClearRecentRequestId;
  1488. const auto finish = [=] {
  1489. (isAttached
  1490. ? _stickersClearRecentAttachedRequestId
  1491. : _stickersClearRecentRequestId) = 0;
  1492. };
  1493. requestId = request(MTPmessages_ClearRecentStickers(
  1494. MTP_flags(flags)
  1495. )).done(finish).fail(finish).send();
  1496. continue;
  1497. }
  1498. auto it = sets.find(removedSetId);
  1499. if (it != sets.cend()) {
  1500. const auto set = it->second.get();
  1501. for (auto i = recent.begin(); i != recent.cend();) {
  1502. if (set->stickers.indexOf(i->first) >= 0) {
  1503. i = recent.erase(i);
  1504. writeRecent = true;
  1505. } else {
  1506. ++i;
  1507. }
  1508. }
  1509. const auto archived = !!(set->flags & Flag::Archived);
  1510. if (!archived) {
  1511. const auto featured = !!(set->flags & Flag::Featured);
  1512. const auto special = !!(set->flags & Flag::Special);
  1513. const auto emoji = !!(set->flags & Flag::Emoji);
  1514. const auto locked = (set->locked > 0);
  1515. const auto setId = set->mtpInput();
  1516. auto requestId = request(MTPmessages_UninstallStickerSet(
  1517. setId
  1518. )).done([=](const MTPBool &result, mtpRequestId requestId) {
  1519. stickerSetDisenabled(requestId);
  1520. }).fail([=](const MTP::Error &error, mtpRequestId requestId) {
  1521. stickerSetDisenabled(requestId);
  1522. }).afterDelay(kSmallDelayMs).send();
  1523. setDisenableRequests.insert(requestId);
  1524. const auto removeIndex = order.indexOf(set->id);
  1525. if (removeIndex >= 0) {
  1526. orderRef.removeAt(removeIndex);
  1527. }
  1528. if (!featured && !special && !emoji && !locked) {
  1529. sets.erase(it);
  1530. } else {
  1531. if (archived) {
  1532. writeArchived = true;
  1533. }
  1534. set->flags &= ~(Flag::Installed | Flag::Archived);
  1535. set->installDate = TimeId(0);
  1536. }
  1537. }
  1538. }
  1539. }
  1540. // Clear all installed flags, set only for sets from order.
  1541. for (auto &[id, set] : sets) {
  1542. const auto archived = !!(set->flags & Flag::Archived);
  1543. const auto thatType = !!(set->flags & Flag::Emoji)
  1544. ? Data::StickersType::Emoji
  1545. : !!(set->flags & Flag::Masks)
  1546. ? Data::StickersType::Masks
  1547. : Data::StickersType::Stickers;
  1548. if (!archived && (type == thatType)) {
  1549. set->flags &= ~Flag::Installed;
  1550. }
  1551. }
  1552. orderRef.clear();
  1553. for (const auto setId : std::as_const(localOrder)) {
  1554. auto it = sets.find(setId);
  1555. if (it == sets.cend()) {
  1556. continue;
  1557. }
  1558. const auto set = it->second.get();
  1559. const auto archived = !!(set->flags & Flag::Archived);
  1560. if (archived && !localRemoved.contains(set->id)) {
  1561. const auto mtpSetId = set->mtpInput();
  1562. const auto requestId = request(MTPmessages_InstallStickerSet(
  1563. mtpSetId,
  1564. MTP_boolFalse()
  1565. )).done([=](
  1566. const MTPmessages_StickerSetInstallResult &result,
  1567. mtpRequestId requestId) {
  1568. stickerSetDisenabled(requestId);
  1569. }).fail([=](
  1570. const MTP::Error &error,
  1571. mtpRequestId requestId) {
  1572. stickerSetDisenabled(requestId);
  1573. }).afterDelay(kSmallDelayMs).send();
  1574. setDisenableRequests.insert(requestId);
  1575. set->flags &= ~Flag::Archived;
  1576. writeArchived = true;
  1577. }
  1578. orderRef.push_back(setId);
  1579. set->flags |= Flag::Installed;
  1580. if (!set->installDate) {
  1581. set->installDate = base::unixtime::now();
  1582. }
  1583. }
  1584. for (auto it = sets.begin(); it != sets.cend();) {
  1585. const auto set = it->second.get();
  1586. if ((set->flags & Flag::Featured)
  1587. || (set->flags & Flag::Installed)
  1588. || (set->flags & Flag::Archived)
  1589. || (set->flags & Flag::Special)
  1590. || (set->flags & Flag::Emoji)
  1591. || (set->locked > 0)) {
  1592. ++it;
  1593. } else {
  1594. it = sets.erase(it);
  1595. }
  1596. }
  1597. auto &storage = local();
  1598. if (writeInstalled) {
  1599. if (type == Data::StickersType::Emoji) {
  1600. storage.writeInstalledCustomEmoji();
  1601. } else if (type == Data::StickersType::Masks) {
  1602. storage.writeInstalledMasks();
  1603. } else {
  1604. storage.writeInstalledStickers();
  1605. }
  1606. }
  1607. if (writeRecent) {
  1608. session().saveSettings();
  1609. }
  1610. if (writeArchived) {
  1611. if (type == Data::StickersType::Emoji) {
  1612. } else if (type == Data::StickersType::Masks) {
  1613. storage.writeArchivedMasks();
  1614. } else {
  1615. storage.writeArchivedStickers();
  1616. }
  1617. }
  1618. if (writeCloudRecent) {
  1619. storage.writeRecentStickers();
  1620. }
  1621. if (writeCloudRecentAttached) {
  1622. storage.writeRecentMasks();
  1623. }
  1624. if (writeFaved) {
  1625. storage.writeFavedStickers();
  1626. }
  1627. _session->data().stickers().notifyUpdated(type);
  1628. if (setDisenableRequests.empty()) {
  1629. stickersSaveOrder();
  1630. } else {
  1631. requestSendDelayed();
  1632. }
  1633. }
  1634. void ApiWrap::joinChannel(not_null<ChannelData*> channel) {
  1635. if (channel->amIn()) {
  1636. session().changes().peerUpdated(
  1637. channel,
  1638. Data::PeerUpdate::Flag::ChannelAmIn);
  1639. } else if (!_channelAmInRequests.contains(channel)) {
  1640. const auto requestId = request(MTPchannels_JoinChannel(
  1641. channel->inputChannel
  1642. )).done([=](const MTPUpdates &result) {
  1643. _channelAmInRequests.remove(channel);
  1644. applyUpdates(result);
  1645. }).fail([=](const MTP::Error &error) {
  1646. const auto &type = error.type();
  1647. const auto show = ShowForPeer(channel);
  1648. if (type == u"CHANNEL_PRIVATE"_q
  1649. && channel->invitePeekExpires()) {
  1650. channel->privateErrorReceived();
  1651. } else if (type == u"CHANNELS_TOO_MUCH"_q) {
  1652. ShowChannelsLimitBox(channel);
  1653. } else {
  1654. const auto text = [&] {
  1655. if (type == u"INVITE_REQUEST_SENT"_q) {
  1656. return channel->isMegagroup()
  1657. ? tr::lng_group_request_sent(tr::now)
  1658. : tr::lng_group_request_sent_channel(tr::now);
  1659. } else if (type == u"CHANNEL_PRIVATE"_q
  1660. || type == u"CHANNEL_PUBLIC_GROUP_NA"_q
  1661. || type == u"USER_BANNED_IN_CHANNEL"_q) {
  1662. return channel->isMegagroup()
  1663. ? tr::lng_group_not_accessible(tr::now)
  1664. : tr::lng_channel_not_accessible(tr::now);
  1665. } else if (type == u"USERS_TOO_MUCH"_q) {
  1666. return tr::lng_group_full(tr::now);
  1667. }
  1668. return QString();
  1669. }();
  1670. if (show && !text.isEmpty()) {
  1671. show->showToast(text, kJoinErrorDuration);
  1672. }
  1673. }
  1674. _channelAmInRequests.remove(channel);
  1675. }).send();
  1676. _channelAmInRequests.emplace(channel, requestId);
  1677. using Flag = ChannelDataFlag;
  1678. chatParticipants().loadSimilarPeers(channel);
  1679. channel->setFlags(channel->flags() | Flag::SimilarExpanded);
  1680. }
  1681. }
  1682. void ApiWrap::leaveChannel(not_null<ChannelData*> channel) {
  1683. if (!channel->amIn()) {
  1684. session().changes().peerUpdated(
  1685. channel,
  1686. Data::PeerUpdate::Flag::ChannelAmIn);
  1687. } else if (!_channelAmInRequests.contains(channel)) {
  1688. auto requestId = request(MTPchannels_LeaveChannel(
  1689. channel->inputChannel
  1690. )).done([=](const MTPUpdates &result) {
  1691. _channelAmInRequests.remove(channel);
  1692. applyUpdates(result);
  1693. }).fail([=] {
  1694. _channelAmInRequests.remove(channel);
  1695. }).send();
  1696. _channelAmInRequests.emplace(channel, requestId);
  1697. }
  1698. }
  1699. void ApiWrap::requestNotifySettings(const MTPInputNotifyPeer &peer) {
  1700. const auto bad = peer.match([](const MTPDinputNotifyUsers &) {
  1701. return false;
  1702. }, [](const MTPDinputNotifyChats &) {
  1703. return false;
  1704. }, [](const MTPDinputNotifyBroadcasts &) {
  1705. return false;
  1706. }, [&](const MTPDinputNotifyPeer &data) {
  1707. if (data.vpeer().type() == mtpc_inputPeerEmpty) {
  1708. LOG(("Api Error: Requesting settings for empty peer."));
  1709. return true;
  1710. }
  1711. return false;
  1712. }, [&](const MTPDinputNotifyForumTopic &data) {
  1713. if (data.vpeer().type() == mtpc_inputPeerEmpty) {
  1714. LOG(("Api Error: Requesting settings for empty peer topic."));
  1715. return true;
  1716. }
  1717. return false;
  1718. });
  1719. if (bad) {
  1720. return;
  1721. }
  1722. const auto peerFromInput = [&](const MTPInputPeer &inputPeer) {
  1723. return inputPeer.match([&](const MTPDinputPeerSelf &) {
  1724. return _session->userPeerId();
  1725. }, [](const MTPDinputPeerEmpty &) {
  1726. return PeerId(0);
  1727. }, [](const MTPDinputPeerChannel &data) {
  1728. return peerFromChannel(data.vchannel_id());
  1729. }, [](const MTPDinputPeerChat &data) {
  1730. return peerFromChat(data.vchat_id());
  1731. }, [](const MTPDinputPeerUser &data) {
  1732. return peerFromUser(data.vuser_id());
  1733. }, [](const auto &) -> PeerId {
  1734. Unexpected("Type in ApiRequest::requestNotifySettings peer.");
  1735. });
  1736. };
  1737. const auto key = peer.match([](const MTPDinputNotifyUsers &) {
  1738. return NotifySettingsKey{ peerFromUser(1) };
  1739. }, [](const MTPDinputNotifyChats &) {
  1740. return NotifySettingsKey{ peerFromChat(1) };
  1741. }, [](const MTPDinputNotifyBroadcasts &) {
  1742. return NotifySettingsKey{ peerFromChannel(1) };
  1743. }, [&](const MTPDinputNotifyPeer &data) {
  1744. return NotifySettingsKey{ peerFromInput(data.vpeer()) };
  1745. }, [&](const MTPDinputNotifyForumTopic &data) {
  1746. return NotifySettingsKey{
  1747. peerFromInput(data.vpeer()),
  1748. data.vtop_msg_id().v,
  1749. };
  1750. });
  1751. if (_notifySettingRequests.contains(key)) {
  1752. return;
  1753. }
  1754. const auto requestId = request(MTPaccount_GetNotifySettings(
  1755. peer
  1756. )).done([=](const MTPPeerNotifySettings &result) {
  1757. _session->data().notifySettings().apply(peer, result);
  1758. _notifySettingRequests.remove(key);
  1759. }).fail([=] {
  1760. _session->data().notifySettings().apply(
  1761. peer,
  1762. MTP_peerNotifySettings(
  1763. MTP_flags(0),
  1764. MTPBool(),
  1765. MTPBool(),
  1766. MTPint(),
  1767. MTPNotificationSound(),
  1768. MTPNotificationSound(),
  1769. MTPNotificationSound(),
  1770. MTPBool(),
  1771. MTPBool(),
  1772. MTPNotificationSound(),
  1773. MTPNotificationSound(),
  1774. MTPNotificationSound()));
  1775. _notifySettingRequests.erase(key);
  1776. }).send();
  1777. _notifySettingRequests.emplace(key, requestId);
  1778. }
  1779. void ApiWrap::updateNotifySettingsDelayed(
  1780. not_null<const Data::Thread*> thread) {
  1781. const auto topic = thread->asTopic();
  1782. if (!topic) {
  1783. return updateNotifySettingsDelayed(thread->peer());
  1784. }
  1785. if (_updateNotifyTopics.emplace(topic).second) {
  1786. topic->destroyed(
  1787. ) | rpl::start_with_next([=] {
  1788. _updateNotifyTopics.remove(topic);
  1789. }, _updateNotifyQueueLifetime);
  1790. _updateNotifyTimer.callOnce(kNotifySettingSaveTimeout);
  1791. }
  1792. }
  1793. void ApiWrap::updateNotifySettingsDelayed(not_null<const PeerData*> peer) {
  1794. if (_updateNotifyPeers.emplace(peer).second) {
  1795. _updateNotifyTimer.callOnce(kNotifySettingSaveTimeout);
  1796. }
  1797. }
  1798. void ApiWrap::updateNotifySettingsDelayed(Data::DefaultNotify type) {
  1799. if (_updateNotifyDefaults.emplace(type).second) {
  1800. _updateNotifyTimer.callOnce(kNotifySettingSaveTimeout);
  1801. }
  1802. }
  1803. void ApiWrap::sendNotifySettingsUpdates() {
  1804. _updateNotifyQueueLifetime.destroy();
  1805. for (const auto topic : base::take(_updateNotifyTopics)) {
  1806. request(MTPaccount_UpdateNotifySettings(
  1807. MTP_inputNotifyForumTopic(
  1808. topic->channel()->input,
  1809. MTP_int(topic->rootId())),
  1810. topic->notify().serialize()
  1811. )).afterDelay(kSmallDelayMs).send();
  1812. }
  1813. for (const auto peer : base::take(_updateNotifyPeers)) {
  1814. request(MTPaccount_UpdateNotifySettings(
  1815. MTP_inputNotifyPeer(peer->input),
  1816. peer->notify().serialize()
  1817. )).afterDelay(kSmallDelayMs).send();
  1818. }
  1819. const auto &settings = session().data().notifySettings();
  1820. for (const auto type : base::take(_updateNotifyDefaults)) {
  1821. request(MTPaccount_UpdateNotifySettings(
  1822. Data::DefaultNotifyToMTP(type),
  1823. settings.defaultSettings(type).serialize()
  1824. )).afterDelay(kSmallDelayMs).send();
  1825. }
  1826. session().mtp().sendAnything();
  1827. }
  1828. void ApiWrap::saveDraftToCloudDelayed(not_null<Data::Thread*> thread) {
  1829. _draftsSaveRequestIds.emplace(base::make_weak(thread), 0);
  1830. if (!_draftsSaveTimer.isActive()) {
  1831. _draftsSaveTimer.callOnce(kSaveCloudDraftTimeout);
  1832. }
  1833. }
  1834. void ApiWrap::updatePrivacyLastSeens() {
  1835. const auto now = base::unixtime::now();
  1836. if (!_session->premium()) {
  1837. _session->data().enumerateUsers([&](not_null<UserData*> user) {
  1838. if (user->isSelf()
  1839. || !user->isLoaded()
  1840. || user->lastseen().isHidden()) {
  1841. return;
  1842. }
  1843. const auto till = user->lastseen().onlineTill();
  1844. user->updateLastseen((till + 3 * 86400 >= now)
  1845. ? Data::LastseenStatus::Recently(true)
  1846. : (till + 7 * 86400 >= now)
  1847. ? Data::LastseenStatus::WithinWeek(true)
  1848. : (till + 30 * 86400 >= now)
  1849. ? Data::LastseenStatus::WithinMonth(true)
  1850. : Data::LastseenStatus::LongAgo(true));
  1851. session().changes().peerUpdated(
  1852. user,
  1853. Data::PeerUpdate::Flag::OnlineStatus);
  1854. session().data().maybeStopWatchForOffline(user);
  1855. });
  1856. }
  1857. if (_contactsStatusesRequestId) {
  1858. request(_contactsStatusesRequestId).cancel();
  1859. }
  1860. _contactsStatusesRequestId = request(MTPcontacts_GetStatuses(
  1861. )).done([=](const MTPVector<MTPContactStatus> &result) {
  1862. _contactsStatusesRequestId = 0;
  1863. for (const auto &status : result.v) {
  1864. const auto &data = status.data();
  1865. const auto userId = UserId(data.vuser_id());
  1866. if (const auto user = _session->data().userLoaded(userId)) {
  1867. const auto status = LastseenFromMTP(
  1868. data.vstatus(),
  1869. user->lastseen());
  1870. if (user->updateLastseen(status)) {
  1871. session().changes().peerUpdated(
  1872. user,
  1873. Data::PeerUpdate::Flag::OnlineStatus);
  1874. }
  1875. }
  1876. }
  1877. }).fail([this] {
  1878. _contactsStatusesRequestId = 0;
  1879. }).send();
  1880. }
  1881. void ApiWrap::clearHistory(not_null<PeerData*> peer, bool revoke) {
  1882. deleteHistory(peer, true, revoke);
  1883. }
  1884. void ApiWrap::deleteConversation(not_null<PeerData*> peer, bool revoke) {
  1885. if (const auto chat = peer->asChat()) {
  1886. request(MTPmessages_DeleteChatUser(
  1887. MTP_flags(0),
  1888. chat->inputChat,
  1889. _session->user()->inputUser
  1890. )).done([=](const MTPUpdates &result) {
  1891. applyUpdates(result);
  1892. deleteHistory(peer, false, revoke);
  1893. }).fail([=] {
  1894. deleteHistory(peer, false, revoke);
  1895. }).send();
  1896. } else {
  1897. deleteHistory(peer, false, revoke);
  1898. }
  1899. }
  1900. void ApiWrap::deleteHistory(
  1901. not_null<PeerData*> peer,
  1902. bool justClear,
  1903. bool revoke) {
  1904. auto deleteTillId = MsgId(0);
  1905. const auto history = _session->data().history(peer);
  1906. if (justClear) {
  1907. // In case of clear history we need to know the last server message.
  1908. while (history->lastMessageKnown()) {
  1909. const auto last = history->lastMessage();
  1910. if (!last) {
  1911. // History is empty.
  1912. return;
  1913. } else if (!last->isRegular()) {
  1914. // Destroy client-side message locally.
  1915. last->destroy();
  1916. } else {
  1917. break;
  1918. }
  1919. }
  1920. if (!history->lastMessageKnown()) {
  1921. history->owner().histories().requestDialogEntry(history, [=] {
  1922. Expects(history->lastMessageKnown());
  1923. deleteHistory(peer, justClear, revoke);
  1924. });
  1925. return;
  1926. }
  1927. deleteTillId = history->lastMessage()->id;
  1928. }
  1929. if (const auto channel = peer->asChannel()) {
  1930. if (!justClear && !revoke) {
  1931. channel->ptsSetWaitingForShortPoll(-1);
  1932. leaveChannel(channel);
  1933. } else {
  1934. if (const auto migrated = peer->migrateFrom()) {
  1935. deleteHistory(migrated, justClear, revoke);
  1936. }
  1937. if (deleteTillId || (!justClear && revoke)) {
  1938. history->owner().histories().deleteAllMessages(
  1939. history,
  1940. deleteTillId,
  1941. justClear,
  1942. revoke);
  1943. }
  1944. }
  1945. } else {
  1946. history->owner().histories().deleteAllMessages(
  1947. history,
  1948. deleteTillId,
  1949. justClear,
  1950. revoke);
  1951. }
  1952. if (!justClear) {
  1953. _session->data().deleteConversationLocally(peer);
  1954. } else if (history) {
  1955. history->clear(History::ClearType::ClearHistory);
  1956. }
  1957. }
  1958. void ApiWrap::applyUpdates(
  1959. const MTPUpdates &updates,
  1960. uint64 sentMessageRandomId) const {
  1961. this->updates().applyUpdates(updates, sentMessageRandomId);
  1962. }
  1963. int ApiWrap::applyAffectedHistory(
  1964. PeerData *peer,
  1965. const MTPmessages_AffectedHistory &result) const {
  1966. const auto &data = result.c_messages_affectedHistory();
  1967. if (const auto channel = peer ? peer->asChannel() : nullptr) {
  1968. channel->ptsUpdateAndApply(data.vpts().v, data.vpts_count().v);
  1969. } else {
  1970. updates().updateAndApply(data.vpts().v, data.vpts_count().v);
  1971. }
  1972. return data.voffset().v;
  1973. }
  1974. void ApiWrap::applyAffectedMessages(
  1975. not_null<PeerData*> peer,
  1976. const MTPmessages_AffectedMessages &result) {
  1977. const auto &data = result.c_messages_affectedMessages();
  1978. if (const auto channel = peer->asChannel()) {
  1979. channel->ptsUpdateAndApply(data.vpts().v, data.vpts_count().v);
  1980. } else {
  1981. applyAffectedMessages(result);
  1982. }
  1983. }
  1984. void ApiWrap::applyAffectedMessages(
  1985. const MTPmessages_AffectedMessages &result) const {
  1986. const auto &data = result.c_messages_affectedMessages();
  1987. updates().updateAndApply(data.vpts().v, data.vpts_count().v);
  1988. }
  1989. void ApiWrap::saveCurrentDraftToCloud() {
  1990. Core::App().materializeLocalDrafts();
  1991. for (const auto &controller : _session->windows()) {
  1992. if (const auto thread = controller->activeChatCurrent().thread()) {
  1993. const auto topic = thread->asTopic();
  1994. if (topic && topic->creating()) {
  1995. continue;
  1996. }
  1997. const auto history = thread->owningHistory();
  1998. _session->local().writeDrafts(history);
  1999. const auto topicRootId = thread->topicRootId();
  2000. const auto localDraft = history->localDraft(topicRootId);
  2001. const auto cloudDraft = history->cloudDraft(topicRootId);
  2002. if (!Data::DraftsAreEqual(localDraft, cloudDraft)
  2003. && !_session->supportMode()) {
  2004. saveDraftToCloudDelayed(thread);
  2005. }
  2006. }
  2007. }
  2008. }
  2009. void ApiWrap::saveDraftsToCloud() {
  2010. for (auto i = begin(_draftsSaveRequestIds); i != end(_draftsSaveRequestIds);) {
  2011. const auto weak = i->first;
  2012. const auto thread = weak.get();
  2013. if (!thread) {
  2014. i = _draftsSaveRequestIds.erase(i);
  2015. continue;
  2016. } else if (i->second) {
  2017. ++i;
  2018. continue; // sent already
  2019. }
  2020. const auto history = thread->owningHistory();
  2021. const auto topicRootId = thread->topicRootId();
  2022. auto cloudDraft = history->cloudDraft(topicRootId);
  2023. auto localDraft = history->localDraft(topicRootId);
  2024. if (cloudDraft && cloudDraft->saveRequestId) {
  2025. request(base::take(cloudDraft->saveRequestId)).cancel();
  2026. }
  2027. if (!_session->supportMode()) {
  2028. cloudDraft = history->createCloudDraft(topicRootId, localDraft);
  2029. } else if (!cloudDraft) {
  2030. cloudDraft = history->createCloudDraft(topicRootId, nullptr);
  2031. }
  2032. auto flags = MTPmessages_SaveDraft::Flags(0);
  2033. auto &textWithTags = cloudDraft->textWithTags;
  2034. if (cloudDraft->webpage.removed) {
  2035. flags |= MTPmessages_SaveDraft::Flag::f_no_webpage;
  2036. } else if (!cloudDraft->webpage.url.isEmpty()) {
  2037. flags |= MTPmessages_SaveDraft::Flag::f_media;
  2038. }
  2039. if (cloudDraft->reply.messageId || cloudDraft->reply.topicRootId) {
  2040. flags |= MTPmessages_SaveDraft::Flag::f_reply_to;
  2041. }
  2042. if (!textWithTags.tags.isEmpty()) {
  2043. flags |= MTPmessages_SaveDraft::Flag::f_entities;
  2044. }
  2045. auto entities = Api::EntitiesToMTP(
  2046. _session,
  2047. TextUtilities::ConvertTextTagsToEntities(textWithTags.tags),
  2048. Api::ConvertOption::SkipLocal);
  2049. history->startSavingCloudDraft(topicRootId);
  2050. cloudDraft->saveRequestId = request(MTPmessages_SaveDraft(
  2051. MTP_flags(flags),
  2052. ReplyToForMTP(history, cloudDraft->reply),
  2053. history->peer->input,
  2054. MTP_string(textWithTags.text),
  2055. entities,
  2056. Data::WebPageForMTP(
  2057. cloudDraft->webpage,
  2058. textWithTags.text.isEmpty()),
  2059. MTP_long(0) // effect
  2060. )).done([=](const MTPBool &result, const MTP::Response &response) {
  2061. const auto requestId = response.requestId;
  2062. history->finishSavingCloudDraft(
  2063. topicRootId,
  2064. UnixtimeFromMsgId(response.outerMsgId));
  2065. if (const auto cloudDraft = history->cloudDraft(topicRootId)) {
  2066. if (cloudDraft->saveRequestId == requestId) {
  2067. cloudDraft->saveRequestId = 0;
  2068. history->draftSavedToCloud(topicRootId);
  2069. }
  2070. }
  2071. const auto i = _draftsSaveRequestIds.find(weak);
  2072. if (i != _draftsSaveRequestIds.cend()
  2073. && i->second == requestId) {
  2074. _draftsSaveRequestIds.erase(i);
  2075. checkQuitPreventFinished();
  2076. }
  2077. }).fail([=](const MTP::Error &error, const MTP::Response &response) {
  2078. const auto requestId = response.requestId;
  2079. history->finishSavingCloudDraft(
  2080. topicRootId,
  2081. UnixtimeFromMsgId(response.outerMsgId));
  2082. if (const auto cloudDraft = history->cloudDraft(topicRootId)) {
  2083. if (cloudDraft->saveRequestId == requestId) {
  2084. history->clearCloudDraft(topicRootId);
  2085. }
  2086. }
  2087. const auto i = _draftsSaveRequestIds.find(weak);
  2088. if (i != _draftsSaveRequestIds.cend()
  2089. && i->second == requestId) {
  2090. _draftsSaveRequestIds.erase(i);
  2091. checkQuitPreventFinished();
  2092. }
  2093. }).send();
  2094. i->second = cloudDraft->saveRequestId;
  2095. ++i;
  2096. }
  2097. }
  2098. bool ApiWrap::isQuitPrevent() {
  2099. if (_draftsSaveRequestIds.empty()) {
  2100. return false;
  2101. }
  2102. LOG(("ApiWrap prevents quit, saving drafts..."));
  2103. saveDraftsToCloud();
  2104. return true;
  2105. }
  2106. void ApiWrap::checkQuitPreventFinished() {
  2107. if (_draftsSaveRequestIds.empty()) {
  2108. if (Core::Quitting()) {
  2109. LOG(("ApiWrap doesn't prevent quit any more."));
  2110. }
  2111. Core::App().quitPreventFinished();
  2112. }
  2113. }
  2114. void ApiWrap::registerModifyRequest(
  2115. const QString &key,
  2116. mtpRequestId requestId) {
  2117. const auto i = _modifyRequests.find(key);
  2118. if (i != end(_modifyRequests)) {
  2119. request(i->second).cancel();
  2120. i->second = requestId;
  2121. } else {
  2122. _modifyRequests.emplace(key, requestId);
  2123. }
  2124. }
  2125. void ApiWrap::clearModifyRequest(const QString &key) {
  2126. _modifyRequests.remove(key);
  2127. }
  2128. void ApiWrap::gotStickerSet(
  2129. uint64 setId,
  2130. const MTPmessages_StickerSet &result) {
  2131. _stickerSetRequests.remove(setId);
  2132. result.match([&](const MTPDmessages_stickerSet &data) {
  2133. _session->data().stickers().feedSetFull(data);
  2134. }, [](const MTPDmessages_stickerSetNotModified &) {
  2135. LOG(("API Error: Unexpected messages.stickerSetNotModified."));
  2136. });
  2137. }
  2138. void ApiWrap::requestWebPageDelayed(not_null<WebPageData*> page) {
  2139. if (page->failed || !page->pendingTill) {
  2140. return;
  2141. }
  2142. _webPagesPending.emplace(page, 0);
  2143. auto left = (page->pendingTill - base::unixtime::now()) * 1000;
  2144. if (!_webPagesTimer.isActive() || left <= _webPagesTimer.remainingTime()) {
  2145. _webPagesTimer.callOnce((left < 0 ? 0 : left) + 1);
  2146. }
  2147. }
  2148. void ApiWrap::clearWebPageRequest(not_null<WebPageData*> page) {
  2149. _webPagesPending.remove(page);
  2150. if (_webPagesPending.empty() && _webPagesTimer.isActive()) {
  2151. _webPagesTimer.cancel();
  2152. }
  2153. }
  2154. void ApiWrap::clearWebPageRequests() {
  2155. _webPagesPending.clear();
  2156. _webPagesTimer.cancel();
  2157. }
  2158. void ApiWrap::resolveWebPages() {
  2159. auto ids = QVector<MTPInputMessage>(); // temp_req_id = -1
  2160. using IndexAndMessageIds = QPair<int32, QVector<MTPInputMessage>>;
  2161. using MessageIdsByChannel = base::flat_map<ChannelData*, IndexAndMessageIds>;
  2162. MessageIdsByChannel idsByChannel; // temp_req_id = -index - 2
  2163. ids.reserve(_webPagesPending.size());
  2164. int32 t = base::unixtime::now(), m = INT_MAX;
  2165. for (auto &[page, requestId] : _webPagesPending) {
  2166. if (requestId > 0) {
  2167. continue;
  2168. }
  2169. if (page->pendingTill <= t) {
  2170. if (const auto item = _session->data().findWebPageItem(page)) {
  2171. if (const auto channel = item->history()->peer->asChannel()) {
  2172. auto channelMap = idsByChannel.find(channel);
  2173. if (channelMap == idsByChannel.cend()) {
  2174. channelMap = idsByChannel.emplace(
  2175. channel,
  2176. IndexAndMessageIds(
  2177. idsByChannel.size(),
  2178. QVector<MTPInputMessage>(
  2179. 1,
  2180. MTP_inputMessageID(MTP_int(item->id))))).first;
  2181. } else {
  2182. channelMap->second.second.push_back(
  2183. MTP_inputMessageID(MTP_int(item->id)));
  2184. }
  2185. requestId = -channelMap->second.first - 2;
  2186. } else {
  2187. ids.push_back(MTP_inputMessageID(MTP_int(item->id)));
  2188. requestId = -1;
  2189. }
  2190. }
  2191. } else {
  2192. m = std::min(m, page->pendingTill - t);
  2193. }
  2194. }
  2195. auto requestId = mtpRequestId(0);
  2196. if (!ids.isEmpty()) {
  2197. requestId = request(MTPmessages_GetMessages(
  2198. MTP_vector<MTPInputMessage>(ids)
  2199. )).done([=](
  2200. const MTPmessages_Messages &result,
  2201. mtpRequestId requestId) {
  2202. gotWebPages(nullptr, result, requestId);
  2203. }).afterDelay(kSmallDelayMs).send();
  2204. }
  2205. QVector<mtpRequestId> reqsByIndex(idsByChannel.size(), 0);
  2206. for (auto i = idsByChannel.cbegin(), e = idsByChannel.cend(); i != e; ++i) {
  2207. reqsByIndex[i->second.first] = request(MTPchannels_GetMessages(
  2208. i->first->inputChannel,
  2209. MTP_vector<MTPInputMessage>(i->second.second)
  2210. )).done([=, channel = i->first](
  2211. const MTPmessages_Messages &result,
  2212. mtpRequestId requestId) {
  2213. gotWebPages(channel, result, requestId);
  2214. }).afterDelay(kSmallDelayMs).send();
  2215. }
  2216. if (requestId || !reqsByIndex.isEmpty()) {
  2217. for (auto &[page, pendingRequestId] : _webPagesPending) {
  2218. if (pendingRequestId > 0) {
  2219. continue;
  2220. } else if (pendingRequestId < 0) {
  2221. if (pendingRequestId == -1) {
  2222. pendingRequestId = requestId;
  2223. } else {
  2224. pendingRequestId = reqsByIndex[-pendingRequestId - 2];
  2225. }
  2226. }
  2227. }
  2228. }
  2229. if (m < INT_MAX) {
  2230. _webPagesTimer.callOnce(std::min(m, 86400) * crl::time(1000));
  2231. }
  2232. }
  2233. template <typename Request>
  2234. void ApiWrap::requestFileReference(
  2235. Data::FileOrigin origin,
  2236. FileReferencesHandler &&handler,
  2237. Request &&data) {
  2238. const auto i = _fileReferenceHandlers.find(origin);
  2239. if (i != end(_fileReferenceHandlers)) {
  2240. i->second.push_back(std::move(handler));
  2241. return;
  2242. }
  2243. auto handlers = std::vector<FileReferencesHandler>();
  2244. handlers.push_back(std::move(handler));
  2245. _fileReferenceHandlers.emplace(origin, std::move(handlers));
  2246. request(std::move(data)).done([=](const auto &result) {
  2247. const auto parsed = Data::GetFileReferences(result);
  2248. for (const auto &p : parsed.data) {
  2249. // Unpack here the parsed pair by hand to workaround a GCC bug.
  2250. // See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87122
  2251. const auto &origin = p.first;
  2252. const auto &reference = p.second;
  2253. const auto documentId = std::get_if<DocumentFileLocationId>(
  2254. &origin);
  2255. if (documentId) {
  2256. _session->data().document(
  2257. documentId->id
  2258. )->refreshFileReference(reference);
  2259. }
  2260. const auto photoId = std::get_if<PhotoFileLocationId>(&origin);
  2261. if (photoId) {
  2262. _session->data().photo(
  2263. photoId->id
  2264. )->refreshFileReference(reference);
  2265. }
  2266. }
  2267. const auto i = _fileReferenceHandlers.find(origin);
  2268. Assert(i != end(_fileReferenceHandlers));
  2269. auto handlers = std::move(i->second);
  2270. _fileReferenceHandlers.erase(i);
  2271. for (auto &handler : handlers) {
  2272. handler(parsed);
  2273. }
  2274. }).fail([=] {
  2275. const auto i = _fileReferenceHandlers.find(origin);
  2276. Assert(i != end(_fileReferenceHandlers));
  2277. auto handlers = std::move(i->second);
  2278. _fileReferenceHandlers.erase(i);
  2279. for (auto &handler : handlers) {
  2280. handler(UpdatedFileReferences());
  2281. }
  2282. }).send();
  2283. }
  2284. void ApiWrap::refreshFileReference(
  2285. Data::FileOrigin origin,
  2286. not_null<Storage::DownloadMtprotoTask*> task,
  2287. int requestId,
  2288. const QByteArray &current) {
  2289. return refreshFileReference(origin, crl::guard(task, [=](
  2290. const UpdatedFileReferences &data) {
  2291. task->refreshFileReferenceFrom(data, requestId, current);
  2292. }));
  2293. }
  2294. void ApiWrap::refreshFileReference(
  2295. Data::FileOrigin origin,
  2296. FileReferencesHandler &&handler) {
  2297. const auto fail = [&] {
  2298. handler(UpdatedFileReferences());
  2299. };
  2300. const auto request = [&](
  2301. auto &&data,
  2302. Fn<void()> &&additional = nullptr) {
  2303. requestFileReference(
  2304. origin,
  2305. std::move(handler),
  2306. std::move(data));
  2307. if (additional) {
  2308. const auto i = _fileReferenceHandlers.find(origin);
  2309. Assert(i != end(_fileReferenceHandlers));
  2310. if (i->second.size() == 1) {
  2311. i->second.push_back([=](auto&&) {
  2312. additional();
  2313. });
  2314. }
  2315. }
  2316. };
  2317. v::match(origin.data, [&](Data::FileOriginMessage data) {
  2318. if (const auto item = _session->data().message(data)) {
  2319. const auto media = item->media();
  2320. const auto storyId = media ? media->storyId() : FullStoryId();
  2321. if (storyId) {
  2322. request(MTPstories_GetStoriesByID(
  2323. _session->data().peer(storyId.peer)->input,
  2324. MTP_vector<MTPint>(1, MTP_int(storyId.story))));
  2325. } else if (item->isScheduled()) {
  2326. const auto realId = _session->scheduledMessages().lookupId(
  2327. item);
  2328. request(MTPmessages_GetScheduledMessages(
  2329. item->history()->peer->input,
  2330. MTP_vector<MTPint>(1, MTP_int(realId))));
  2331. } else if (item->isBusinessShortcut()) {
  2332. const auto &shortcuts = _session->data().shortcutMessages();
  2333. const auto realId = shortcuts.lookupId(item);
  2334. request(MTPmessages_GetQuickReplyMessages(
  2335. MTP_flags(MTPmessages_GetQuickReplyMessages::Flag::f_id),
  2336. MTP_int(item->shortcutId()),
  2337. MTP_vector<MTPint>(1, MTP_int(realId)),
  2338. MTP_long(0)));
  2339. } else if (const auto channel = item->history()->peer->asChannel()) {
  2340. request(MTPchannels_GetMessages(
  2341. channel->inputChannel,
  2342. MTP_vector<MTPInputMessage>(
  2343. 1,
  2344. MTP_inputMessageID(MTP_int(item->id)))));
  2345. } else {
  2346. request(MTPmessages_GetMessages(
  2347. MTP_vector<MTPInputMessage>(
  2348. 1,
  2349. MTP_inputMessageID(MTP_int(item->id)))));
  2350. }
  2351. } else {
  2352. fail();
  2353. }
  2354. }, [&](Data::FileOriginUserPhoto data) {
  2355. if (const auto user = _session->data().user(data.userId)) {
  2356. request(MTPphotos_GetUserPhotos(
  2357. user->inputUser,
  2358. MTP_int(-1),
  2359. MTP_long(data.photoId),
  2360. MTP_int(1)));
  2361. } else {
  2362. fail();
  2363. }
  2364. }, [&](Data::FileOriginFullUser data) {
  2365. if (const auto user = _session->data().user(data.userId)) {
  2366. request(MTPusers_GetFullUser(user->inputUser));
  2367. } else {
  2368. fail();
  2369. }
  2370. }, [&](Data::FileOriginPeerPhoto data) {
  2371. fail();
  2372. }, [&](Data::FileOriginStickerSet data) {
  2373. const auto isRecentAttached
  2374. = (data.setId == Data::Stickers::CloudRecentAttachedSetId);
  2375. if (data.setId == Data::Stickers::CloudRecentSetId
  2376. || data.setId == Data::Stickers::RecentSetId
  2377. || isRecentAttached) {
  2378. auto done = [=] { crl::on_main(_session, [=] {
  2379. if (isRecentAttached) {
  2380. local().writeRecentMasks();
  2381. } else {
  2382. local().writeRecentStickers();
  2383. }
  2384. }); };
  2385. request(MTPmessages_GetRecentStickers(
  2386. MTP_flags(isRecentAttached
  2387. ? MTPmessages_GetRecentStickers::Flag::f_attached
  2388. : MTPmessages_GetRecentStickers::Flags(0)),
  2389. MTP_long(0)),
  2390. std::move(done));
  2391. } else if (data.setId == Data::Stickers::FavedSetId) {
  2392. request(MTPmessages_GetFavedStickers(MTP_long(0)),
  2393. [=] { crl::on_main(_session, [=] { local().writeFavedStickers(); }); });
  2394. } else {
  2395. request(MTPmessages_GetStickerSet(
  2396. MTP_inputStickerSetID(
  2397. MTP_long(data.setId),
  2398. MTP_long(data.accessHash)),
  2399. MTP_int(0)), // hash
  2400. [=] { crl::on_main(_session, [=] {
  2401. local().writeInstalledStickers();
  2402. local().writeRecentStickers();
  2403. local().writeFavedStickers();
  2404. }); });
  2405. }
  2406. }, [&](Data::FileOriginSavedGifs data) {
  2407. request(
  2408. MTPmessages_GetSavedGifs(MTP_long(0)),
  2409. [=] { crl::on_main(_session, [=] { local().writeSavedGifs(); }); });
  2410. }, [&](Data::FileOriginWallpaper data) {
  2411. const auto useSlug = data.ownerId
  2412. && (data.ownerId != session().userId())
  2413. && !data.slug.isEmpty();
  2414. request(MTPaccount_GetWallPaper(useSlug
  2415. ? MTP_inputWallPaperSlug(MTP_string(data.slug))
  2416. : MTP_inputWallPaper(
  2417. MTP_long(data.paperId),
  2418. MTP_long(data.accessHash))));
  2419. }, [&](Data::FileOriginTheme data) {
  2420. request(MTPaccount_GetTheme(
  2421. MTP_string(Data::CloudThemes::Format()),
  2422. MTP_inputTheme(
  2423. MTP_long(data.themeId),
  2424. MTP_long(data.accessHash))));
  2425. }, [&](Data::FileOriginRingtones data) {
  2426. request(MTPaccount_GetSavedRingtones(MTP_long(0)));
  2427. }, [&](Data::FileOriginPremiumPreviews data) {
  2428. request(MTPhelp_GetPremiumPromo());
  2429. }, [&](Data::FileOriginWebPage data) {
  2430. request(MTPmessages_GetWebPage(
  2431. MTP_string(data.url),
  2432. MTP_int(0)));
  2433. }, [&](Data::FileOriginStory data) {
  2434. request(MTPstories_GetStoriesByID(
  2435. _session->data().peer(data.peer)->input,
  2436. MTP_vector<MTPint>(1, MTP_int(data.story))));
  2437. }, [&](v::null_t) {
  2438. fail();
  2439. });
  2440. }
  2441. void ApiWrap::gotWebPages(ChannelData *channel, const MTPmessages_Messages &result, mtpRequestId req) {
  2442. WebPageData::ApplyChanges(_session, channel, result);
  2443. for (auto i = _webPagesPending.begin(); i != _webPagesPending.cend();) {
  2444. if (i->second == req) {
  2445. if (i->first->pendingTill > 0) {
  2446. i->first->pendingTill = 0;
  2447. i->first->failed = 1;
  2448. _session->data().notifyWebPageUpdateDelayed(i->first);
  2449. }
  2450. i = _webPagesPending.erase(i);
  2451. } else {
  2452. ++i;
  2453. }
  2454. }
  2455. _session->data().sendWebPageGamePollNotifications();
  2456. }
  2457. void ApiWrap::updateStickers() {
  2458. const auto now = crl::now();
  2459. requestStickers(now);
  2460. requestRecentStickers(now, false);
  2461. requestFavedStickers(now);
  2462. requestFeaturedStickers(now);
  2463. }
  2464. void ApiWrap::updateSavedGifs() {
  2465. const auto now = crl::now();
  2466. requestSavedGifs(now);
  2467. }
  2468. void ApiWrap::updateMasks() {
  2469. const auto now = crl::now();
  2470. requestMasks(now);
  2471. requestRecentStickers(now, true);
  2472. }
  2473. void ApiWrap::updateCustomEmoji() {
  2474. const auto now = crl::now();
  2475. requestCustomEmoji(now);
  2476. requestFeaturedEmoji(now);
  2477. }
  2478. void ApiWrap::requestSpecialStickersForce(
  2479. bool faved,
  2480. bool recent,
  2481. bool attached) {
  2482. if (faved) {
  2483. requestFavedStickers(std::nullopt);
  2484. } else if (recent || attached) {
  2485. requestRecentStickers(std::nullopt, attached);
  2486. }
  2487. }
  2488. void ApiWrap::setGroupStickerSet(
  2489. not_null<ChannelData*> megagroup,
  2490. const StickerSetIdentifier &set) {
  2491. Expects(megagroup->mgInfo != nullptr);
  2492. megagroup->mgInfo->stickerSet = set;
  2493. request(MTPchannels_SetStickers(
  2494. megagroup->inputChannel,
  2495. Data::InputStickerSet(set)
  2496. )).send();
  2497. _session->data().stickers().notifyUpdated(Data::StickersType::Stickers);
  2498. }
  2499. void ApiWrap::setGroupEmojiSet(
  2500. not_null<ChannelData*> megagroup,
  2501. const StickerSetIdentifier &set) {
  2502. Expects(megagroup->mgInfo != nullptr);
  2503. megagroup->mgInfo->emojiSet = set;
  2504. request(MTPchannels_SetEmojiStickers(
  2505. megagroup->inputChannel,
  2506. Data::InputStickerSet(set)
  2507. )).send();
  2508. _session->changes().peerUpdated(
  2509. megagroup,
  2510. Data::PeerUpdate::Flag::EmojiSet);
  2511. _session->data().stickers().notifyUpdated(Data::StickersType::Emoji);
  2512. }
  2513. std::vector<not_null<DocumentData*>> *ApiWrap::stickersByEmoji(
  2514. const QString &key) {
  2515. const auto it = _stickersByEmoji.find(key);
  2516. const auto sendRequest = [&] {
  2517. if (it == _stickersByEmoji.end()) {
  2518. return true;
  2519. }
  2520. const auto received = it->second.received;
  2521. const auto now = crl::now();
  2522. return (received > 0)
  2523. && (received + kStickersByEmojiInvalidateTimeout) <= now;
  2524. }();
  2525. if (sendRequest) {
  2526. const auto hash = (it != _stickersByEmoji.end())
  2527. ? it->second.hash
  2528. : uint64(0);
  2529. request(MTPmessages_GetStickers(
  2530. MTP_string(key),
  2531. MTP_long(hash)
  2532. )).done([=](const MTPmessages_Stickers &result) {
  2533. if (result.type() == mtpc_messages_stickersNotModified) {
  2534. return;
  2535. }
  2536. Assert(result.type() == mtpc_messages_stickers);
  2537. const auto &data = result.c_messages_stickers();
  2538. auto &entry = _stickersByEmoji[key];
  2539. entry.list.clear();
  2540. entry.list.reserve(data.vstickers().v.size());
  2541. for (const auto &sticker : data.vstickers().v) {
  2542. const auto document = _session->data().processDocument(
  2543. sticker);
  2544. if (document->sticker()) {
  2545. entry.list.push_back(document);
  2546. }
  2547. }
  2548. entry.hash = data.vhash().v;
  2549. entry.received = crl::now();
  2550. _session->data().stickers().notifyUpdated(
  2551. Data::StickersType::Stickers);
  2552. }).send();
  2553. }
  2554. if (it == _stickersByEmoji.end()) {
  2555. _stickersByEmoji.emplace(key, StickersByEmoji());
  2556. } else if (it->second.received > 0) {
  2557. return &it->second.list;
  2558. }
  2559. return nullptr;
  2560. }
  2561. void ApiWrap::requestStickers(TimeId now) {
  2562. if (!_session->data().stickers().updateNeeded(now)
  2563. || _stickersUpdateRequest) {
  2564. return;
  2565. }
  2566. const auto done = [=](const MTPmessages_AllStickers &result) {
  2567. _session->data().stickers().setLastUpdate(crl::now());
  2568. _stickersUpdateRequest = 0;
  2569. result.match([&](const MTPDmessages_allStickersNotModified&) {
  2570. }, [&](const MTPDmessages_allStickers &data) {
  2571. _session->data().stickers().setsReceived(
  2572. data.vsets().v,
  2573. data.vhash().v);
  2574. });
  2575. };
  2576. _stickersUpdateRequest = request(MTPmessages_GetAllStickers(
  2577. MTP_long(Api::CountStickersHash(_session, true))
  2578. )).done(done).fail([=] {
  2579. LOG(("App Fail: Failed to get stickers!"));
  2580. done(MTP_messages_allStickersNotModified());
  2581. }).send();
  2582. }
  2583. void ApiWrap::requestMasks(TimeId now) {
  2584. if (!_session->data().stickers().masksUpdateNeeded(now)
  2585. || _masksUpdateRequest) {
  2586. return;
  2587. }
  2588. const auto done = [=](const MTPmessages_AllStickers &result) {
  2589. _session->data().stickers().setLastMasksUpdate(crl::now());
  2590. _masksUpdateRequest = 0;
  2591. result.match([&](const MTPDmessages_allStickersNotModified&) {
  2592. }, [&](const MTPDmessages_allStickers &data) {
  2593. _session->data().stickers().masksReceived(
  2594. data.vsets().v,
  2595. data.vhash().v);
  2596. });
  2597. };
  2598. _masksUpdateRequest = request(MTPmessages_GetMaskStickers(
  2599. MTP_long(Api::CountMasksHash(_session, true))
  2600. )).done(done).fail([=] {
  2601. LOG(("App Fail: Failed to get masks!"));
  2602. done(MTP_messages_allStickersNotModified());
  2603. }).send();
  2604. }
  2605. void ApiWrap::requestCustomEmoji(TimeId now) {
  2606. if (!_session->data().stickers().emojiUpdateNeeded(now)
  2607. || _customEmojiUpdateRequest) {
  2608. return;
  2609. }
  2610. const auto done = [=](const MTPmessages_AllStickers &result) {
  2611. _session->data().stickers().setLastEmojiUpdate(crl::now());
  2612. _customEmojiUpdateRequest = 0;
  2613. result.match([&](const MTPDmessages_allStickersNotModified&) {
  2614. }, [&](const MTPDmessages_allStickers &data) {
  2615. _session->data().stickers().emojiReceived(
  2616. data.vsets().v,
  2617. data.vhash().v);
  2618. });
  2619. };
  2620. _customEmojiUpdateRequest = request(MTPmessages_GetEmojiStickers(
  2621. MTP_long(Api::CountCustomEmojiHash(_session, true))
  2622. )).done(done).fail([=] {
  2623. LOG(("App Fail: Failed to get custom emoji!"));
  2624. done(MTP_messages_allStickersNotModified());
  2625. }).send();
  2626. }
  2627. void ApiWrap::requestRecentStickers(
  2628. std::optional<TimeId> now,
  2629. bool attached) {
  2630. const auto needed = !now
  2631. ? true
  2632. : attached
  2633. ? _session->data().stickers().recentAttachedUpdateNeeded(*now)
  2634. : _session->data().stickers().recentUpdateNeeded(*now);
  2635. if (!needed) {
  2636. return;
  2637. }
  2638. const auto requestId = [=]() -> mtpRequestId & {
  2639. return attached
  2640. ? _recentAttachedStickersUpdateRequest
  2641. : _recentStickersUpdateRequest;
  2642. };
  2643. if (requestId()) {
  2644. return;
  2645. }
  2646. const auto finish = [=] {
  2647. auto &stickers = _session->data().stickers();
  2648. if (attached) {
  2649. stickers.setLastRecentAttachedUpdate(crl::now());
  2650. } else {
  2651. stickers.setLastRecentUpdate(crl::now());
  2652. }
  2653. requestId() = 0;
  2654. };
  2655. const auto flags = attached
  2656. ? MTPmessages_getRecentStickers::Flag::f_attached
  2657. : MTPmessages_getRecentStickers::Flags(0);
  2658. requestId() = request(MTPmessages_GetRecentStickers(
  2659. MTP_flags(flags),
  2660. MTP_long(now ? Api::CountRecentStickersHash(_session, attached) : 0)
  2661. )).done([=](const MTPmessages_RecentStickers &result) {
  2662. finish();
  2663. switch (result.type()) {
  2664. case mtpc_messages_recentStickersNotModified: return;
  2665. case mtpc_messages_recentStickers: {
  2666. auto &d = result.c_messages_recentStickers();
  2667. _session->data().stickers().specialSetReceived(
  2668. attached
  2669. ? Data::Stickers::CloudRecentAttachedSetId
  2670. : Data::Stickers::CloudRecentSetId,
  2671. tr::lng_recent_stickers(tr::now),
  2672. d.vstickers().v,
  2673. d.vhash().v,
  2674. d.vpacks().v,
  2675. d.vdates().v);
  2676. } return;
  2677. default: Unexpected("Type in ApiWrap::recentStickersDone()");
  2678. }
  2679. }).fail([=] {
  2680. finish();
  2681. LOG(("App Fail: Failed to get recent stickers!"));
  2682. }).send();
  2683. }
  2684. void ApiWrap::requestFavedStickers(std::optional<TimeId> now) {
  2685. if (now) {
  2686. if (!_session->data().stickers().favedUpdateNeeded(*now)
  2687. || _favedStickersUpdateRequest) {
  2688. return;
  2689. }
  2690. }
  2691. _favedStickersUpdateRequest = request(MTPmessages_GetFavedStickers(
  2692. MTP_long(now ? Api::CountFavedStickersHash(_session) : 0)
  2693. )).done([=](const MTPmessages_FavedStickers &result) {
  2694. _session->data().stickers().setLastFavedUpdate(crl::now());
  2695. _favedStickersUpdateRequest = 0;
  2696. switch (result.type()) {
  2697. case mtpc_messages_favedStickersNotModified: return;
  2698. case mtpc_messages_favedStickers: {
  2699. auto &d = result.c_messages_favedStickers();
  2700. _session->data().stickers().specialSetReceived(
  2701. Data::Stickers::FavedSetId,
  2702. Lang::Hard::FavedSetTitle(),
  2703. d.vstickers().v,
  2704. d.vhash().v,
  2705. d.vpacks().v);
  2706. } return;
  2707. default: Unexpected("Type in ApiWrap::favedStickersDone()");
  2708. }
  2709. }).fail([=] {
  2710. _session->data().stickers().setLastFavedUpdate(crl::now());
  2711. _favedStickersUpdateRequest = 0;
  2712. LOG(("App Fail: Failed to get faved stickers!"));
  2713. }).send();
  2714. }
  2715. void ApiWrap::requestFeaturedStickers(TimeId now) {
  2716. if (!_session->data().stickers().featuredUpdateNeeded(now)
  2717. || _featuredStickersUpdateRequest) {
  2718. return;
  2719. }
  2720. _featuredStickersUpdateRequest = request(MTPmessages_GetFeaturedStickers(
  2721. MTP_long(Api::CountFeaturedStickersHash(_session))
  2722. )).done([=](const MTPmessages_FeaturedStickers &result) {
  2723. _featuredStickersUpdateRequest = 0;
  2724. _session->data().stickers().featuredSetsReceived(result);
  2725. }).fail([=] {
  2726. _featuredStickersUpdateRequest = 0;
  2727. _session->data().stickers().setLastFeaturedUpdate(crl::now());
  2728. LOG(("App Fail: Failed to get featured stickers!"));
  2729. }).send();
  2730. }
  2731. void ApiWrap::requestFeaturedEmoji(TimeId now) {
  2732. if (!_session->data().stickers().featuredEmojiUpdateNeeded(now)
  2733. || _featuredEmojiUpdateRequest) {
  2734. return;
  2735. }
  2736. _featuredEmojiUpdateRequest = request(
  2737. MTPmessages_GetFeaturedEmojiStickers(
  2738. MTP_long(Api::CountFeaturedStickersHash(_session)))
  2739. ).done([=](const MTPmessages_FeaturedStickers &result) {
  2740. _featuredEmojiUpdateRequest = 0;
  2741. _session->data().stickers().featuredEmojiSetsReceived(result);
  2742. }).fail([=] {
  2743. _featuredEmojiUpdateRequest = 0;
  2744. _session->data().stickers().setLastFeaturedEmojiUpdate(crl::now());
  2745. LOG(("App Fail: Failed to get featured emoji!"));
  2746. }).send();
  2747. }
  2748. void ApiWrap::requestSavedGifs(TimeId now) {
  2749. if (!_session->data().stickers().savedGifsUpdateNeeded(now)
  2750. || _savedGifsUpdateRequest) {
  2751. return;
  2752. }
  2753. _savedGifsUpdateRequest = request(MTPmessages_GetSavedGifs(
  2754. MTP_long(Api::CountSavedGifsHash(_session))
  2755. )).done([=](const MTPmessages_SavedGifs &result) {
  2756. _session->data().stickers().setLastSavedGifsUpdate(crl::now());
  2757. _savedGifsUpdateRequest = 0;
  2758. switch (result.type()) {
  2759. case mtpc_messages_savedGifsNotModified: return;
  2760. case mtpc_messages_savedGifs: {
  2761. auto &d = result.c_messages_savedGifs();
  2762. _session->data().stickers().gifsReceived(
  2763. d.vgifs().v,
  2764. d.vhash().v);
  2765. } return;
  2766. default: Unexpected("Type in ApiWrap::savedGifsDone()");
  2767. }
  2768. }).fail([=] {
  2769. _session->data().stickers().setLastSavedGifsUpdate(crl::now());
  2770. _savedGifsUpdateRequest = 0;
  2771. LOG(("App Fail: Failed to get saved gifs!"));
  2772. }).send();
  2773. }
  2774. void ApiWrap::readFeaturedSetDelayed(uint64 setId) {
  2775. if (!_featuredSetsRead.contains(setId)) {
  2776. _featuredSetsRead.insert(setId);
  2777. _featuredSetsReadTimer.callOnce(kReadFeaturedSetsTimeout);
  2778. }
  2779. }
  2780. void ApiWrap::readFeaturedSets() {
  2781. const auto &sets = _session->data().stickers().sets();
  2782. auto count = _session->data().stickers().featuredSetsUnreadCount();
  2783. QVector<MTPlong> wrappedIds;
  2784. wrappedIds.reserve(_featuredSetsRead.size());
  2785. for (const auto setId : _featuredSetsRead) {
  2786. const auto it = sets.find(setId);
  2787. if (it != sets.cend()) {
  2788. it->second->flags &= ~Data::StickersSetFlag::Unread;
  2789. wrappedIds.append(MTP_long(setId));
  2790. if (count) {
  2791. --count;
  2792. }
  2793. }
  2794. }
  2795. _featuredSetsRead.clear();
  2796. if (!wrappedIds.empty()) {
  2797. auto requestData = MTPmessages_ReadFeaturedStickers(
  2798. MTP_vector<MTPlong>(wrappedIds));
  2799. request(std::move(requestData)).done([=] {
  2800. local().writeFeaturedStickers();
  2801. _session->data().stickers().notifyUpdated(
  2802. Data::StickersType::Stickers);
  2803. }).send();
  2804. _session->data().stickers().setFeaturedSetsUnreadCount(count);
  2805. }
  2806. }
  2807. void ApiWrap::resolveJumpToDate(
  2808. Dialogs::Key chat,
  2809. const QDate &date,
  2810. Fn<void(not_null<PeerData*>, MsgId)> callback) {
  2811. if (const auto peer = chat.peer()) {
  2812. const auto topic = chat.topic();
  2813. const auto rootId = topic ? topic->rootId() : 0;
  2814. resolveJumpToHistoryDate(peer, rootId, date, std::move(callback));
  2815. }
  2816. }
  2817. template <typename Callback>
  2818. void ApiWrap::requestMessageAfterDate(
  2819. not_null<PeerData*> peer,
  2820. MsgId topicRootId,
  2821. const QDate &date,
  2822. Callback &&callback) {
  2823. // API returns a message with date <= offset_date.
  2824. // So we request a message with offset_date = desired_date - 1 and add_offset = -1.
  2825. // This should give us the first message with date >= desired_date.
  2826. const auto offsetId = 0;
  2827. const auto offsetDate = static_cast<int>(date.startOfDay().toSecsSinceEpoch()) - 1;
  2828. const auto addOffset = -1;
  2829. const auto limit = 1;
  2830. const auto maxId = 0;
  2831. const auto minId = 0;
  2832. const auto historyHash = uint64(0);
  2833. auto send = [&](auto &&serialized) {
  2834. request(std::move(serialized)).done([
  2835. =,
  2836. callback = std::forward<Callback>(callback)
  2837. ](const MTPmessages_Messages &result) {
  2838. const auto handleMessages = [&](auto &messages) {
  2839. _session->data().processUsers(messages.vusers());
  2840. _session->data().processChats(messages.vchats());
  2841. return &messages.vmessages().v;
  2842. };
  2843. const auto list = result.match([&](
  2844. const MTPDmessages_messages &data) {
  2845. return handleMessages(data);
  2846. }, [&](const MTPDmessages_messagesSlice &data) {
  2847. return handleMessages(data);
  2848. }, [&](const MTPDmessages_channelMessages &data) {
  2849. if (const auto channel = peer->asChannel()) {
  2850. channel->ptsReceived(data.vpts().v);
  2851. channel->processTopics(data.vtopics());
  2852. } else {
  2853. LOG(("API Error: received messages.channelMessages when "
  2854. "no channel was passed! (ApiWrap::jumpToDate)"));
  2855. }
  2856. return handleMessages(data);
  2857. }, [&](const MTPDmessages_messagesNotModified &) {
  2858. LOG(("API Error: received messages.messagesNotModified! "
  2859. "(ApiWrap::jumpToDate)"));
  2860. return (const QVector<MTPMessage>*)nullptr;
  2861. });
  2862. if (list) {
  2863. _session->data().processMessages(
  2864. *list,
  2865. NewMessageType::Existing);
  2866. for (const auto &message : *list) {
  2867. if (DateFromMessage(message) >= offsetDate) {
  2868. callback(IdFromMessage(message));
  2869. return;
  2870. }
  2871. }
  2872. }
  2873. callback(ShowAtUnreadMsgId);
  2874. }).send();
  2875. };
  2876. if (topicRootId) {
  2877. send(MTPmessages_GetReplies(
  2878. peer->input,
  2879. MTP_int(topicRootId),
  2880. MTP_int(offsetId),
  2881. MTP_int(offsetDate),
  2882. MTP_int(addOffset),
  2883. MTP_int(limit),
  2884. MTP_int(maxId),
  2885. MTP_int(minId),
  2886. MTP_long(historyHash)));
  2887. } else {
  2888. send(MTPmessages_GetHistory(
  2889. peer->input,
  2890. MTP_int(offsetId),
  2891. MTP_int(offsetDate),
  2892. MTP_int(addOffset),
  2893. MTP_int(limit),
  2894. MTP_int(maxId),
  2895. MTP_int(minId),
  2896. MTP_long(historyHash)));
  2897. }
  2898. }
  2899. void ApiWrap::resolveJumpToHistoryDate(
  2900. not_null<PeerData*> peer,
  2901. MsgId topicRootId,
  2902. const QDate &date,
  2903. Fn<void(not_null<PeerData*>, MsgId)> callback) {
  2904. if (const auto channel = peer->migrateTo()) {
  2905. return resolveJumpToHistoryDate(
  2906. channel,
  2907. topicRootId,
  2908. date,
  2909. std::move(callback));
  2910. }
  2911. const auto jumpToDateInPeer = [=] {
  2912. requestMessageAfterDate(peer, topicRootId, date, [=](MsgId itemId) {
  2913. callback(peer, itemId);
  2914. });
  2915. };
  2916. if (const auto chat = topicRootId ? nullptr : peer->migrateFrom()) {
  2917. requestMessageAfterDate(chat, 0, date, [=](MsgId itemId) {
  2918. if (itemId) {
  2919. callback(chat, itemId);
  2920. } else {
  2921. jumpToDateInPeer();
  2922. }
  2923. });
  2924. } else {
  2925. jumpToDateInPeer();
  2926. }
  2927. }
  2928. void ApiWrap::requestHistory(
  2929. not_null<History*> history,
  2930. MsgId messageId,
  2931. SliceType slice) {
  2932. const auto peer = history->peer;
  2933. const auto key = HistoryRequest{
  2934. peer,
  2935. messageId,
  2936. slice,
  2937. };
  2938. if (_historyRequests.contains(key)) {
  2939. return;
  2940. }
  2941. const auto prepared = Api::PrepareHistoryRequest(peer, messageId, slice);
  2942. auto &histories = history->owner().histories();
  2943. const auto requestType = Data::Histories::RequestType::History;
  2944. histories.sendRequest(history, requestType, [=](Fn<void()> finish) {
  2945. return request(
  2946. std::move(prepared)
  2947. ).done([=](const Api::HistoryRequestResult &result) {
  2948. _historyRequests.remove(key);
  2949. auto parsed = Api::ParseHistoryResult(
  2950. peer,
  2951. messageId,
  2952. slice,
  2953. result);
  2954. history->messages().addSlice(
  2955. std::move(parsed.messageIds),
  2956. parsed.noSkipRange,
  2957. parsed.fullCount);
  2958. finish();
  2959. }).fail([=] {
  2960. _historyRequests.remove(key);
  2961. finish();
  2962. }).send();
  2963. });
  2964. _historyRequests.emplace(key);
  2965. }
  2966. void ApiWrap::requestSharedMedia(
  2967. not_null<PeerData*> peer,
  2968. MsgId topicRootId,
  2969. SharedMediaType type,
  2970. MsgId messageId,
  2971. SliceType slice) {
  2972. const auto key = SharedMediaRequest{
  2973. peer,
  2974. topicRootId,
  2975. type,
  2976. messageId,
  2977. slice,
  2978. };
  2979. if (_sharedMediaRequests.contains(key)) {
  2980. return;
  2981. }
  2982. const auto prepared = Api::PrepareSearchRequest(
  2983. peer,
  2984. topicRootId,
  2985. type,
  2986. QString(),
  2987. messageId,
  2988. slice);
  2989. if (!prepared) {
  2990. return;
  2991. }
  2992. const auto history = _session->data().history(peer);
  2993. auto &histories = history->owner().histories();
  2994. const auto requestType = Data::Histories::RequestType::History;
  2995. histories.sendRequest(history, requestType, [=](Fn<void()> finish) {
  2996. return request(
  2997. std::move(*prepared)
  2998. ).done([=](const Api::SearchRequestResult &result) {
  2999. _sharedMediaRequests.remove(key);
  3000. auto parsed = Api::ParseSearchResult(
  3001. peer,
  3002. type,
  3003. messageId,
  3004. slice,
  3005. result);
  3006. sharedMediaDone(peer, topicRootId, type, std::move(parsed));
  3007. finish();
  3008. }).fail([=] {
  3009. _sharedMediaRequests.remove(key);
  3010. finish();
  3011. }).send();
  3012. });
  3013. _sharedMediaRequests.emplace(key);
  3014. }
  3015. void ApiWrap::sharedMediaDone(
  3016. not_null<PeerData*> peer,
  3017. MsgId topicRootId,
  3018. SharedMediaType type,
  3019. Api::SearchResult &&parsed) {
  3020. const auto topic = peer->forumTopicFor(topicRootId);
  3021. if (topicRootId && !topic) {
  3022. return;
  3023. }
  3024. const auto hasMessages = !parsed.messageIds.empty();
  3025. _session->storage().add(Storage::SharedMediaAddSlice(
  3026. peer->id,
  3027. topicRootId,
  3028. type,
  3029. std::move(parsed.messageIds),
  3030. parsed.noSkipRange,
  3031. parsed.fullCount
  3032. ));
  3033. if (type == SharedMediaType::Pinned && hasMessages) {
  3034. peer->owner().history(peer)->setHasPinnedMessages(true);
  3035. if (topic) {
  3036. topic->setHasPinnedMessages(true);
  3037. }
  3038. }
  3039. }
  3040. mtpRequestId ApiWrap::requestGlobalMedia(
  3041. Storage::SharedMediaType type,
  3042. const QString &query,
  3043. int32 offsetRate,
  3044. Data::MessagePosition offsetPosition,
  3045. Fn<void(Api::GlobalMediaResult)> done) {
  3046. auto prepared = Api::PrepareGlobalMediaRequest(
  3047. _session,
  3048. offsetRate,
  3049. offsetPosition,
  3050. type,
  3051. query);
  3052. if (!prepared) {
  3053. done({});
  3054. return 0;
  3055. }
  3056. return request(
  3057. std::move(*prepared)
  3058. ).done([=](const Api::SearchRequestResult &result) {
  3059. done(Api::ParseGlobalMediaResult(_session, result));
  3060. }).fail([=] {
  3061. done({});
  3062. }).send();
  3063. }
  3064. void ApiWrap::sendAction(const SendAction &action) {
  3065. if (!action.options.scheduled
  3066. && !action.options.shortcutId
  3067. && !action.replaceMediaOf) {
  3068. const auto topicRootId = action.replyTo.topicRootId;
  3069. const auto topic = topicRootId
  3070. ? action.history->peer->forumTopicFor(topicRootId)
  3071. : nullptr;
  3072. if (topic) {
  3073. topic->readTillEnd();
  3074. } else {
  3075. _session->data().histories().readInbox(action.history);
  3076. }
  3077. action.history->getReadyFor(ShowAtTheEndMsgId);
  3078. }
  3079. _sendActions.fire_copy(action);
  3080. }
  3081. void ApiWrap::finishForwarding(const SendAction &action) {
  3082. const auto history = action.history;
  3083. const auto topicRootId = action.replyTo.topicRootId;
  3084. auto toForward = history->resolveForwardDraft(topicRootId);
  3085. if (!toForward.items.empty()) {
  3086. const auto error = GetErrorForSending(
  3087. history->peer,
  3088. {
  3089. .topicRootId = topicRootId,
  3090. .forward = &toForward.items,
  3091. });
  3092. if (error) {
  3093. return;
  3094. }
  3095. forwardMessages(std::move(toForward), action);
  3096. history->setForwardDraft(topicRootId, {});
  3097. }
  3098. _session->data().sendHistoryChangeNotifications();
  3099. if (!action.options.shortcutId) {
  3100. _session->changes().historyUpdated(
  3101. history,
  3102. (action.options.scheduled
  3103. ? Data::HistoryUpdate::Flag::ScheduledSent
  3104. : Data::HistoryUpdate::Flag::MessageSent));
  3105. }
  3106. }
  3107. void ApiWrap::forwardMessages(
  3108. Data::ResolvedForwardDraft &&draft,
  3109. SendAction action,
  3110. FnMut<void()> &&successCallback) {
  3111. Expects(!draft.items.empty());
  3112. auto &histories = _session->data().histories();
  3113. struct SharedCallback {
  3114. int requestsLeft = 0;
  3115. FnMut<void()> callback;
  3116. };
  3117. const auto shared = successCallback
  3118. ? std::make_shared<SharedCallback>()
  3119. : std::shared_ptr<SharedCallback>();
  3120. if (successCallback) {
  3121. shared->callback = std::move(successCallback);
  3122. }
  3123. const auto count = int(draft.items.size());
  3124. const auto genClientSideMessage = action.generateLocal
  3125. && (count < 2)
  3126. && (draft.options == Data::ForwardOptions::PreserveInfo);
  3127. const auto history = action.history;
  3128. const auto peer = history->peer;
  3129. if (!action.options.scheduled && !action.options.shortcutId) {
  3130. histories.readInbox(history);
  3131. }
  3132. const auto sendAs = action.options.sendAs;
  3133. const auto silentPost = ShouldSendSilent(peer, action.options);
  3134. using SendFlag = MTPmessages_ForwardMessages::Flag;
  3135. auto flags = MessageFlags();
  3136. auto sendFlags = SendFlag() | SendFlag();
  3137. FillMessagePostFlags(action, peer, flags);
  3138. if (silentPost) {
  3139. sendFlags |= SendFlag::f_silent;
  3140. }
  3141. if (action.options.scheduled) {
  3142. flags |= MessageFlag::IsOrWasScheduled;
  3143. sendFlags |= SendFlag::f_schedule_date;
  3144. }
  3145. if (action.options.shortcutId) {
  3146. flags |= MessageFlag::ShortcutMessage;
  3147. sendFlags |= SendFlag::f_quick_reply_shortcut;
  3148. }
  3149. if (draft.options != Data::ForwardOptions::PreserveInfo) {
  3150. sendFlags |= SendFlag::f_drop_author;
  3151. }
  3152. if (draft.options == Data::ForwardOptions::NoNamesAndCaptions) {
  3153. sendFlags |= SendFlag::f_drop_media_captions;
  3154. }
  3155. if (sendAs) {
  3156. sendFlags |= SendFlag::f_send_as;
  3157. }
  3158. const auto kGeneralId = Data::ForumTopic::kGeneralId;
  3159. const auto topicRootId = action.replyTo.topicRootId;
  3160. const auto topMsgId = (topicRootId == kGeneralId)
  3161. ? MsgId(0)
  3162. : topicRootId;
  3163. if (topMsgId) {
  3164. sendFlags |= SendFlag::f_top_msg_id;
  3165. }
  3166. auto forwardFrom = draft.items.front()->history()->peer;
  3167. auto ids = QVector<MTPint>();
  3168. auto randomIds = QVector<MTPlong>();
  3169. auto localIds = std::shared_ptr<base::flat_map<uint64, FullMsgId>>();
  3170. const auto sendAccumulated = [&] {
  3171. if (shared) {
  3172. ++shared->requestsLeft;
  3173. }
  3174. const auto requestType = Data::Histories::RequestType::Send;
  3175. const auto idsCopy = localIds;
  3176. const auto scheduled = action.options.scheduled;
  3177. const auto starsPaid = std::min(
  3178. action.options.starsApproved,
  3179. int(ids.size() * peer->starsPerMessageChecked()));
  3180. auto oneFlags = sendFlags;
  3181. if (starsPaid) {
  3182. action.options.starsApproved -= starsPaid;
  3183. oneFlags |= SendFlag::f_allow_paid_stars;
  3184. }
  3185. histories.sendRequest(history, requestType, [=](Fn<void()> finish) {
  3186. history->sendRequestId = request(MTPmessages_ForwardMessages(
  3187. MTP_flags(oneFlags),
  3188. forwardFrom->input,
  3189. MTP_vector<MTPint>(ids),
  3190. MTP_vector<MTPlong>(randomIds),
  3191. peer->input,
  3192. MTP_int(topMsgId),
  3193. MTP_int(action.options.scheduled),
  3194. (sendAs ? sendAs->input : MTP_inputPeerEmpty()),
  3195. Data::ShortcutIdToMTP(_session, action.options.shortcutId),
  3196. MTPint(), // video_timestamp
  3197. MTP_long(starsPaid)
  3198. )).done([=](const MTPUpdates &result) {
  3199. if (!scheduled) {
  3200. this->updates().checkForSentToScheduled(result);
  3201. }
  3202. applyUpdates(result);
  3203. if (shared && !--shared->requestsLeft) {
  3204. shared->callback();
  3205. }
  3206. finish();
  3207. }).fail([=](const MTP::Error &error) {
  3208. if (idsCopy) {
  3209. for (const auto &[randomId, itemId] : *idsCopy) {
  3210. sendMessageFail(error, peer, randomId, itemId);
  3211. }
  3212. } else {
  3213. sendMessageFail(error, peer);
  3214. }
  3215. finish();
  3216. }).afterRequest(
  3217. history->sendRequestId
  3218. ).send();
  3219. return history->sendRequestId;
  3220. });
  3221. ids.resize(0);
  3222. randomIds.resize(0);
  3223. localIds = nullptr;
  3224. };
  3225. ids.reserve(count);
  3226. randomIds.reserve(count);
  3227. for (const auto item : draft.items) {
  3228. const auto randomId = base::RandomValue<uint64>();
  3229. if (genClientSideMessage) {
  3230. const auto newId = FullMsgId(
  3231. peer->id,
  3232. _session->data().nextLocalMessageId());
  3233. history->addNewLocalMessage({
  3234. .id = newId.msg,
  3235. .flags = flags,
  3236. .from = NewMessageFromId(action),
  3237. .replyTo = { .topicRootId = topMsgId },
  3238. .date = NewMessageDate(action.options),
  3239. .shortcutId = action.options.shortcutId,
  3240. .starsPaid = action.options.starsApproved,
  3241. .postAuthor = NewMessagePostAuthor(action),
  3242. // forwarded messages don't have effects
  3243. //.effectId = action.options.effectId,
  3244. }, item);
  3245. _session->data().registerMessageRandomId(randomId, newId);
  3246. if (!localIds) {
  3247. localIds = std::make_shared<base::flat_map<uint64, FullMsgId>>();
  3248. }
  3249. localIds->emplace(randomId, newId);
  3250. }
  3251. const auto newFrom = item->history()->peer;
  3252. if (forwardFrom != newFrom) {
  3253. sendAccumulated();
  3254. forwardFrom = newFrom;
  3255. }
  3256. ids.push_back(MTP_int(item->id));
  3257. randomIds.push_back(MTP_long(randomId));
  3258. }
  3259. sendAccumulated();
  3260. _session->data().sendHistoryChangeNotifications();
  3261. }
  3262. void ApiWrap::shareContact(
  3263. const QString &phone,
  3264. const QString &firstName,
  3265. const QString &lastName,
  3266. const SendAction &action,
  3267. Fn<void(bool)> done) {
  3268. const auto userId = UserId(0);
  3269. sendSharedContact(
  3270. phone,
  3271. firstName,
  3272. lastName,
  3273. userId,
  3274. action,
  3275. std::move(done));
  3276. }
  3277. void ApiWrap::shareContact(
  3278. not_null<UserData*> user,
  3279. const SendAction &action,
  3280. Fn<void(bool)> done) {
  3281. const auto userId = peerToUser(user->id);
  3282. const auto phone = _session->data().findContactPhone(user);
  3283. if (phone.isEmpty()) {
  3284. if (done) {
  3285. done(false);
  3286. }
  3287. return;
  3288. }
  3289. return sendSharedContact(
  3290. phone,
  3291. user->firstName,
  3292. user->lastName,
  3293. userId,
  3294. action,
  3295. std::move(done));
  3296. }
  3297. void ApiWrap::sendSharedContact(
  3298. const QString &phone,
  3299. const QString &firstName,
  3300. const QString &lastName,
  3301. UserId userId,
  3302. const SendAction &action,
  3303. Fn<void(bool)> done) {
  3304. sendAction(action);
  3305. const auto history = action.history;
  3306. const auto peer = history->peer;
  3307. const auto newId = FullMsgId(
  3308. peer->id,
  3309. _session->data().nextLocalMessageId());
  3310. auto flags = NewMessageFlags(peer);
  3311. if (action.replyTo) {
  3312. flags |= MessageFlag::HasReplyInfo;
  3313. }
  3314. FillMessagePostFlags(action, peer, flags);
  3315. if (action.options.scheduled) {
  3316. flags |= MessageFlag::IsOrWasScheduled;
  3317. }
  3318. if (action.options.shortcutId) {
  3319. flags |= MessageFlag::ShortcutMessage;
  3320. }
  3321. const auto item = history->addNewLocalMessage({
  3322. .id = newId.msg,
  3323. .flags = flags,
  3324. .from = NewMessageFromId(action),
  3325. .replyTo = action.replyTo,
  3326. .date = NewMessageDate(action.options),
  3327. .shortcutId = action.options.shortcutId,
  3328. .starsPaid = action.options.starsApproved,
  3329. .postAuthor = NewMessagePostAuthor(action),
  3330. .effectId = action.options.effectId,
  3331. }, TextWithEntities(), MTP_messageMediaContact(
  3332. MTP_string(phone),
  3333. MTP_string(firstName),
  3334. MTP_string(lastName),
  3335. MTP_string(), // vcard
  3336. MTP_long(userId.bare)));
  3337. const auto media = MTP_inputMediaContact(
  3338. MTP_string(phone),
  3339. MTP_string(firstName),
  3340. MTP_string(lastName),
  3341. MTP_string()); // vcard
  3342. sendMedia(item, media, action.options, std::move(done));
  3343. _session->data().sendHistoryChangeNotifications();
  3344. _session->changes().historyUpdated(
  3345. history,
  3346. (action.options.scheduled
  3347. ? Data::HistoryUpdate::Flag::ScheduledSent
  3348. : Data::HistoryUpdate::Flag::MessageSent));
  3349. }
  3350. void ApiWrap::sendVoiceMessage(
  3351. QByteArray result,
  3352. VoiceWaveform waveform,
  3353. crl::time duration,
  3354. bool video,
  3355. const SendAction &action) {
  3356. const auto caption = TextWithTags();
  3357. const auto to = FileLoadTaskOptions(action);
  3358. _fileLoader->addTask(std::make_unique<FileLoadTask>(
  3359. &session(),
  3360. result,
  3361. duration,
  3362. waveform,
  3363. video,
  3364. to,
  3365. caption));
  3366. }
  3367. void ApiWrap::editMedia(
  3368. Ui::PreparedList &&list,
  3369. SendMediaType type,
  3370. TextWithTags &&caption,
  3371. const SendAction &action) {
  3372. if (list.files.empty()) return;
  3373. auto &file = list.files.front();
  3374. const auto to = FileLoadTaskOptions(action);
  3375. _fileLoader->addTask(std::make_unique<FileLoadTask>(
  3376. &session(),
  3377. file.path,
  3378. file.content,
  3379. std::move(file.information),
  3380. (file.videoCover
  3381. ? std::make_unique<FileLoadTask>(
  3382. &session(),
  3383. file.videoCover->path,
  3384. file.videoCover->content,
  3385. std::move(file.videoCover->information),
  3386. nullptr,
  3387. SendMediaType::Photo,
  3388. to,
  3389. TextWithTags(),
  3390. false)
  3391. : nullptr),
  3392. type,
  3393. to,
  3394. caption,
  3395. file.spoiler));
  3396. }
  3397. void ApiWrap::sendFiles(
  3398. Ui::PreparedList &&list,
  3399. SendMediaType type,
  3400. TextWithTags &&caption,
  3401. std::shared_ptr<SendingAlbum> album,
  3402. const SendAction &action) {
  3403. const auto haveCaption = !caption.text.isEmpty();
  3404. if (haveCaption
  3405. && !list.canAddCaption(
  3406. album != nullptr,
  3407. type == SendMediaType::Photo)) {
  3408. auto message = MessageToSend(action);
  3409. message.textWithTags = base::take(caption);
  3410. message.action.clearDraft = false;
  3411. sendMessage(std::move(message));
  3412. }
  3413. const auto to = FileLoadTaskOptions(action);
  3414. if (album) {
  3415. album->options = to.options;
  3416. }
  3417. auto tasks = std::vector<std::unique_ptr<Task>>();
  3418. tasks.reserve(list.files.size());
  3419. for (auto &file : list.files) {
  3420. const auto uploadWithType = !album
  3421. ? type
  3422. : (file.type == Ui::PreparedFile::Type::Photo
  3423. && type != SendMediaType::File)
  3424. ? SendMediaType::Photo
  3425. : SendMediaType::File;
  3426. tasks.push_back(std::make_unique<FileLoadTask>(
  3427. &session(),
  3428. file.path,
  3429. file.content,
  3430. std::move(file.information),
  3431. (file.videoCover
  3432. ? std::make_unique<FileLoadTask>(
  3433. &session(),
  3434. file.videoCover->path,
  3435. file.videoCover->content,
  3436. std::move(file.videoCover->information),
  3437. nullptr,
  3438. SendMediaType::Photo,
  3439. to,
  3440. TextWithTags(),
  3441. false,
  3442. nullptr)
  3443. : nullptr),
  3444. uploadWithType,
  3445. to,
  3446. caption,
  3447. file.spoiler,
  3448. album));
  3449. caption = TextWithTags();
  3450. }
  3451. if (album) {
  3452. _sendingAlbums.emplace(album->groupId, album);
  3453. album->items.reserve(tasks.size());
  3454. for (const auto &task : tasks) {
  3455. album->items.emplace_back(task->id());
  3456. }
  3457. }
  3458. _fileLoader->addTasks(std::move(tasks));
  3459. }
  3460. void ApiWrap::sendFile(
  3461. const QByteArray &fileContent,
  3462. SendMediaType type,
  3463. const SendAction &action) {
  3464. const auto to = FileLoadTaskOptions(action);
  3465. auto caption = TextWithTags();
  3466. const auto spoiler = false;
  3467. const auto information = nullptr;
  3468. const auto videoCover = nullptr;
  3469. _fileLoader->addTask(std::make_unique<FileLoadTask>(
  3470. &session(),
  3471. QString(),
  3472. fileContent,
  3473. information,
  3474. videoCover,
  3475. type,
  3476. to,
  3477. caption,
  3478. spoiler));
  3479. }
  3480. void ApiWrap::sendUploadedPhoto(
  3481. FullMsgId localId,
  3482. Api::RemoteFileInfo info,
  3483. Api::SendOptions options) {
  3484. if (const auto item = _session->data().message(localId)) {
  3485. const auto media = Api::PrepareUploadedPhoto(item, std::move(info));
  3486. if (const auto groupId = item->groupId()) {
  3487. uploadAlbumMedia(item, groupId, media);
  3488. } else {
  3489. sendMedia(item, media, options);
  3490. }
  3491. }
  3492. }
  3493. void ApiWrap::sendUploadedDocument(
  3494. FullMsgId localId,
  3495. Api::RemoteFileInfo info,
  3496. Api::SendOptions options) {
  3497. if (const auto item = _session->data().message(localId)) {
  3498. if (!item->media() || !item->media()->document()) {
  3499. return;
  3500. }
  3501. const auto media = Api::PrepareUploadedDocument(
  3502. item,
  3503. std::move(info));
  3504. const auto groupId = item->groupId();
  3505. if (groupId) {
  3506. uploadAlbumMedia(item, groupId, media);
  3507. } else {
  3508. sendMedia(item, media, options);
  3509. }
  3510. }
  3511. }
  3512. void ApiWrap::cancelLocalItem(not_null<HistoryItem*> item) {
  3513. Expects(item->isSending());
  3514. if (const auto groupId = item->groupId()) {
  3515. sendAlbumWithCancelled(item, groupId);
  3516. }
  3517. }
  3518. void ApiWrap::sendShortcutMessages(
  3519. not_null<PeerData*> peer,
  3520. BusinessShortcutId id) {
  3521. auto ids = QVector<MTPint>();
  3522. auto randomIds = QVector<MTPlong>();
  3523. request(MTPmessages_SendQuickReplyMessages(
  3524. peer->input,
  3525. MTP_int(id),
  3526. MTP_vector<MTPint>(ids),
  3527. MTP_vector<MTPlong>(randomIds)
  3528. )).done([=](const MTPUpdates &result) {
  3529. applyUpdates(result);
  3530. }).fail([=](const MTP::Error &error) {
  3531. }).send();
  3532. }
  3533. void ApiWrap::sendMessage(MessageToSend &&message) {
  3534. const auto history = message.action.history;
  3535. const auto peer = history->peer;
  3536. auto &textWithTags = message.textWithTags;
  3537. auto action = message.action;
  3538. action.generateLocal = true;
  3539. sendAction(action);
  3540. const auto clearCloudDraft = action.clearDraft;
  3541. const auto draftTopicRootId = action.replyTo.topicRootId;
  3542. const auto replyTo = action.replyTo.messageId
  3543. ? peer->owner().message(action.replyTo.messageId)
  3544. : nullptr;
  3545. const auto topicRootId = draftTopicRootId
  3546. ? draftTopicRootId
  3547. : replyTo
  3548. ? replyTo->topicRootId()
  3549. : Data::ForumTopic::kGeneralId;
  3550. const auto topic = peer->forumTopicFor(topicRootId);
  3551. if (!(topic ? Data::CanSendTexts(topic) : Data::CanSendTexts(peer))
  3552. || Api::SendDice(message)) {
  3553. return;
  3554. }
  3555. local().saveRecentSentHashtags(textWithTags.text);
  3556. auto sending = TextWithEntities();
  3557. auto left = TextWithEntities {
  3558. textWithTags.text,
  3559. TextUtilities::ConvertTextTagsToEntities(textWithTags.tags)
  3560. };
  3561. auto prepareFlags = Ui::ItemTextOptions(
  3562. history,
  3563. _session->user()).flags;
  3564. TextUtilities::PrepareForSending(left, prepareFlags);
  3565. HistoryItem *lastMessage = nullptr;
  3566. auto &histories = history->owner().histories();
  3567. const auto exactWebPage = !message.webPage.url.isEmpty();
  3568. auto isFirst = true;
  3569. while (TextUtilities::CutPart(sending, left, MaxMessageSize)
  3570. || (isFirst && exactWebPage)) {
  3571. TextUtilities::Trim(left);
  3572. const auto isLast = left.empty();
  3573. auto newId = FullMsgId(
  3574. peer->id,
  3575. _session->data().nextLocalMessageId());
  3576. auto randomId = base::RandomValue<uint64>();
  3577. TextUtilities::Trim(sending);
  3578. _session->data().registerMessageRandomId(randomId, newId);
  3579. _session->data().registerMessageSentData(
  3580. randomId,
  3581. peer->id,
  3582. sending.text);
  3583. MTPstring msgText(MTP_string(sending.text));
  3584. auto flags = NewMessageFlags(peer);
  3585. auto sendFlags = MTPmessages_SendMessage::Flags(0);
  3586. auto mediaFlags = MTPmessages_SendMedia::Flags(0);
  3587. if (action.replyTo) {
  3588. flags |= MessageFlag::HasReplyInfo;
  3589. sendFlags |= MTPmessages_SendMessage::Flag::f_reply_to;
  3590. mediaFlags |= MTPmessages_SendMedia::Flag::f_reply_to;
  3591. }
  3592. const auto ignoreWebPage = message.webPage.removed
  3593. || (exactWebPage && !isLast);
  3594. const auto manualWebPage = exactWebPage
  3595. && !ignoreWebPage
  3596. && (message.webPage.manual || (isLast && !isFirst));
  3597. MTPMessageMedia media = MTP_messageMediaEmpty();
  3598. if (ignoreWebPage) {
  3599. sendFlags |= MTPmessages_SendMessage::Flag::f_no_webpage;
  3600. } else if (exactWebPage) {
  3601. using PageFlag = MTPDmessageMediaWebPage::Flag;
  3602. using PendingFlag = MTPDwebPagePending::Flag;
  3603. const auto &fields = message.webPage;
  3604. const auto page = _session->data().webpage(fields.id);
  3605. media = MTP_messageMediaWebPage(
  3606. MTP_flags(PageFlag()
  3607. | (manualWebPage ? PageFlag::f_manual : PageFlag())
  3608. | (fields.forceLargeMedia
  3609. ? PageFlag::f_force_large_media
  3610. : PageFlag())
  3611. | (fields.forceSmallMedia
  3612. ? PageFlag::f_force_small_media
  3613. : PageFlag())),
  3614. MTP_webPagePending(
  3615. MTP_flags(PendingFlag::f_url),
  3616. MTP_long(fields.id),
  3617. MTP_string(fields.url),
  3618. MTP_int(page->pendingTill)));
  3619. }
  3620. const auto silentPost = ShouldSendSilent(peer, action.options);
  3621. FillMessagePostFlags(action, peer, flags);
  3622. if ((exactWebPage && !ignoreWebPage && message.webPage.invert)
  3623. || action.options.invertCaption) {
  3624. flags |= MessageFlag::InvertMedia;
  3625. sendFlags |= MTPmessages_SendMessage::Flag::f_invert_media;
  3626. mediaFlags |= MTPmessages_SendMedia::Flag::f_invert_media;
  3627. }
  3628. if (silentPost) {
  3629. sendFlags |= MTPmessages_SendMessage::Flag::f_silent;
  3630. mediaFlags |= MTPmessages_SendMedia::Flag::f_silent;
  3631. }
  3632. const auto sentEntities = Api::EntitiesToMTP(
  3633. _session,
  3634. sending.entities,
  3635. Api::ConvertOption::SkipLocal);
  3636. if (!sentEntities.v.isEmpty()) {
  3637. sendFlags |= MTPmessages_SendMessage::Flag::f_entities;
  3638. mediaFlags |= MTPmessages_SendMedia::Flag::f_entities;
  3639. }
  3640. if (clearCloudDraft) {
  3641. sendFlags |= MTPmessages_SendMessage::Flag::f_clear_draft;
  3642. mediaFlags |= MTPmessages_SendMedia::Flag::f_clear_draft;
  3643. history->clearCloudDraft(draftTopicRootId);
  3644. history->startSavingCloudDraft(draftTopicRootId);
  3645. }
  3646. const auto sendAs = action.options.sendAs;
  3647. if (sendAs) {
  3648. sendFlags |= MTPmessages_SendMessage::Flag::f_send_as;
  3649. mediaFlags |= MTPmessages_SendMedia::Flag::f_send_as;
  3650. }
  3651. if (action.options.scheduled) {
  3652. flags |= MessageFlag::IsOrWasScheduled;
  3653. sendFlags |= MTPmessages_SendMessage::Flag::f_schedule_date;
  3654. mediaFlags |= MTPmessages_SendMedia::Flag::f_schedule_date;
  3655. }
  3656. if (action.options.shortcutId) {
  3657. flags |= MessageFlag::ShortcutMessage;
  3658. sendFlags |= MTPmessages_SendMessage::Flag::f_quick_reply_shortcut;
  3659. mediaFlags |= MTPmessages_SendMedia::Flag::f_quick_reply_shortcut;
  3660. }
  3661. if (action.options.effectId) {
  3662. sendFlags |= MTPmessages_SendMessage::Flag::f_effect;
  3663. mediaFlags |= MTPmessages_SendMedia::Flag::f_effect;
  3664. }
  3665. const auto starsPaid = std::min(
  3666. peer->starsPerMessageChecked(),
  3667. action.options.starsApproved);
  3668. if (starsPaid) {
  3669. action.options.starsApproved -= starsPaid;
  3670. sendFlags |= MTPmessages_SendMessage::Flag::f_allow_paid_stars;
  3671. mediaFlags |= MTPmessages_SendMedia::Flag::f_allow_paid_stars;
  3672. }
  3673. lastMessage = history->addNewLocalMessage({
  3674. .id = newId.msg,
  3675. .flags = flags,
  3676. .from = NewMessageFromId(action),
  3677. .replyTo = action.replyTo,
  3678. .date = NewMessageDate(action.options),
  3679. .shortcutId = action.options.shortcutId,
  3680. .starsPaid = starsPaid,
  3681. .postAuthor = NewMessagePostAuthor(action),
  3682. .effectId = action.options.effectId,
  3683. }, sending, media);
  3684. const auto done = [=](
  3685. const MTPUpdates &result,
  3686. const MTP::Response &response) {
  3687. if (clearCloudDraft) {
  3688. history->finishSavingCloudDraft(
  3689. draftTopicRootId,
  3690. UnixtimeFromMsgId(response.outerMsgId));
  3691. }
  3692. };
  3693. const auto fail = [=](
  3694. const MTP::Error &error,
  3695. const MTP::Response &response) {
  3696. if (error.type() == u"MESSAGE_EMPTY"_q) {
  3697. lastMessage->destroy();
  3698. } else {
  3699. sendMessageFail(error, peer, randomId, newId);
  3700. }
  3701. if (clearCloudDraft) {
  3702. history->finishSavingCloudDraft(
  3703. draftTopicRootId,
  3704. UnixtimeFromMsgId(response.outerMsgId));
  3705. }
  3706. };
  3707. const auto mtpShortcut = Data::ShortcutIdToMTP(
  3708. _session,
  3709. action.options.shortcutId);
  3710. if (exactWebPage
  3711. && !ignoreWebPage
  3712. && (manualWebPage || sending.empty())) {
  3713. histories.sendPreparedMessage(
  3714. history,
  3715. action.replyTo,
  3716. randomId,
  3717. Data::Histories::PrepareMessage<MTPmessages_SendMedia>(
  3718. MTP_flags(mediaFlags),
  3719. peer->input,
  3720. Data::Histories::ReplyToPlaceholder(),
  3721. Data::WebPageForMTP(message.webPage, true),
  3722. msgText,
  3723. MTP_long(randomId),
  3724. MTPReplyMarkup(),
  3725. sentEntities,
  3726. MTP_int(action.options.scheduled),
  3727. (sendAs ? sendAs->input : MTP_inputPeerEmpty()),
  3728. mtpShortcut,
  3729. MTP_long(action.options.effectId),
  3730. MTP_long(starsPaid)
  3731. ), done, fail);
  3732. } else {
  3733. histories.sendPreparedMessage(
  3734. history,
  3735. action.replyTo,
  3736. randomId,
  3737. Data::Histories::PrepareMessage<MTPmessages_SendMessage>(
  3738. MTP_flags(sendFlags),
  3739. peer->input,
  3740. Data::Histories::ReplyToPlaceholder(),
  3741. msgText,
  3742. MTP_long(randomId),
  3743. MTPReplyMarkup(),
  3744. sentEntities,
  3745. MTP_int(action.options.scheduled),
  3746. (sendAs ? sendAs->input : MTP_inputPeerEmpty()),
  3747. mtpShortcut,
  3748. MTP_long(action.options.effectId),
  3749. MTP_long(starsPaid)
  3750. ), done, fail);
  3751. }
  3752. isFirst = false;
  3753. }
  3754. finishForwarding(action);
  3755. }
  3756. void ApiWrap::sendBotStart(
  3757. std::shared_ptr<Ui::Show> show,
  3758. not_null<UserData*> bot,
  3759. PeerData *chat,
  3760. const QString &startTokenForChat) {
  3761. Expects(bot->isBot());
  3762. if (chat && chat->isChannel() && !chat->isMegagroup()) {
  3763. ShowAddParticipantsError(show, "USER_BOT", chat, bot);
  3764. return;
  3765. }
  3766. auto &info = bot->botInfo;
  3767. const auto token = chat ? startTokenForChat : info->startToken;
  3768. if (token.isEmpty()) {
  3769. auto message = MessageToSend(
  3770. Api::SendAction(_session->data().history(chat
  3771. ? chat
  3772. : bot.get())));
  3773. message.textWithTags = { u"/start"_q, TextWithTags::Tags() };
  3774. if (chat) {
  3775. message.textWithTags.text += '@' + bot->username();
  3776. }
  3777. sendMessage(std::move(message));
  3778. return;
  3779. }
  3780. const auto randomId = base::RandomValue<uint64>();
  3781. if (!chat) {
  3782. info->startToken = QString();
  3783. }
  3784. request(MTPmessages_StartBot(
  3785. bot->inputUser,
  3786. chat ? chat->input : MTP_inputPeerEmpty(),
  3787. MTP_long(randomId),
  3788. MTP_string(token)
  3789. )).done([=](const MTPUpdates &result) {
  3790. applyUpdates(result);
  3791. }).fail([=](const MTP::Error &error) {
  3792. if (chat) {
  3793. const auto type = error.type();
  3794. ShowAddParticipantsError(show, type, chat, bot);
  3795. }
  3796. }).send();
  3797. }
  3798. void ApiWrap::sendInlineResult(
  3799. not_null<UserData*> bot,
  3800. not_null<InlineBots::Result*> data,
  3801. SendAction action,
  3802. std::optional<MsgId> localMessageId,
  3803. Fn<void(bool)> done) {
  3804. sendAction(action);
  3805. const auto history = action.history;
  3806. const auto peer = history->peer;
  3807. const auto newId = FullMsgId(
  3808. peer->id,
  3809. localMessageId
  3810. ? (*localMessageId)
  3811. : _session->data().nextLocalMessageId());
  3812. const auto randomId = base::RandomValue<uint64>();
  3813. const auto topicRootId = action.replyTo.messageId
  3814. ? action.replyTo.topicRootId
  3815. : 0;
  3816. using SendFlag = MTPmessages_SendInlineBotResult::Flag;
  3817. auto flags = NewMessageFlags(peer);
  3818. auto sendFlags = SendFlag::f_clear_draft | SendFlag();
  3819. if (action.replyTo) {
  3820. flags |= MessageFlag::HasReplyInfo;
  3821. sendFlags |= SendFlag::f_reply_to;
  3822. }
  3823. const auto silentPost = ShouldSendSilent(peer, action.options);
  3824. FillMessagePostFlags(action, peer, flags);
  3825. if (silentPost) {
  3826. sendFlags |= SendFlag::f_silent;
  3827. }
  3828. if (action.options.scheduled) {
  3829. flags |= MessageFlag::IsOrWasScheduled;
  3830. sendFlags |= SendFlag::f_schedule_date;
  3831. }
  3832. if (action.options.shortcutId) {
  3833. flags |= MessageFlag::ShortcutMessage;
  3834. sendFlags |= SendFlag::f_quick_reply_shortcut;
  3835. }
  3836. if (action.options.hideViaBot) {
  3837. sendFlags |= SendFlag::f_hide_via;
  3838. }
  3839. const auto starsPaid = std::min(
  3840. peer->starsPerMessageChecked(),
  3841. action.options.starsApproved);
  3842. if (starsPaid) {
  3843. action.options.starsApproved -= starsPaid;
  3844. sendFlags |= SendFlag::f_allow_paid_stars;
  3845. }
  3846. const auto sendAs = action.options.sendAs;
  3847. if (sendAs) {
  3848. sendFlags |= MTPmessages_SendInlineBotResult::Flag::f_send_as;
  3849. }
  3850. _session->data().registerMessageRandomId(randomId, newId);
  3851. data->addToHistory(history, {
  3852. .id = newId.msg,
  3853. .flags = flags,
  3854. .from = NewMessageFromId(action),
  3855. .replyTo = action.replyTo,
  3856. .date = NewMessageDate(action.options),
  3857. .shortcutId = action.options.shortcutId,
  3858. .starsPaid = starsPaid,
  3859. .viaBotId = ((bot && !action.options.hideViaBot)
  3860. ? peerToUser(bot->id)
  3861. : UserId()),
  3862. .postAuthor = NewMessagePostAuthor(action),
  3863. });
  3864. history->clearCloudDraft(topicRootId);
  3865. history->startSavingCloudDraft(topicRootId);
  3866. auto &histories = history->owner().histories();
  3867. histories.sendPreparedMessage(
  3868. history,
  3869. action.replyTo,
  3870. randomId,
  3871. Data::Histories::PrepareMessage<MTPmessages_SendInlineBotResult>(
  3872. MTP_flags(sendFlags),
  3873. peer->input,
  3874. Data::Histories::ReplyToPlaceholder(),
  3875. MTP_long(randomId),
  3876. MTP_long(data->getQueryId()),
  3877. MTP_string(data->getId()),
  3878. MTP_int(action.options.scheduled),
  3879. (sendAs ? sendAs->input : MTP_inputPeerEmpty()),
  3880. Data::ShortcutIdToMTP(_session, action.options.shortcutId),
  3881. MTP_long(starsPaid)
  3882. ), [=](const MTPUpdates &result, const MTP::Response &response) {
  3883. history->finishSavingCloudDraft(
  3884. topicRootId,
  3885. UnixtimeFromMsgId(response.outerMsgId));
  3886. if (done) {
  3887. done(true);
  3888. }
  3889. }, [=](const MTP::Error &error, const MTP::Response &response) {
  3890. sendMessageFail(error, peer, randomId, newId);
  3891. history->finishSavingCloudDraft(
  3892. topicRootId,
  3893. UnixtimeFromMsgId(response.outerMsgId));
  3894. if (done) {
  3895. done(false);
  3896. }
  3897. });
  3898. finishForwarding(action);
  3899. }
  3900. void ApiWrap::uploadAlbumMedia(
  3901. not_null<HistoryItem*> item,
  3902. const MessageGroupId &groupId,
  3903. const MTPInputMedia &media) {
  3904. const auto localId = item->fullId();
  3905. const auto failed = [=] {
  3906. };
  3907. request(MTPmessages_UploadMedia(
  3908. MTP_flags(0),
  3909. MTPstring(), // business_connection_id
  3910. item->history()->peer->input,
  3911. media
  3912. )).done([=](const MTPMessageMedia &result) {
  3913. const auto item = _session->data().message(localId);
  3914. if (!item) {
  3915. failed();
  3916. return;
  3917. }
  3918. auto spoiler = false;
  3919. if (const auto media = item->media()) {
  3920. spoiler = media->hasSpoiler();
  3921. if (const auto photo = media->photo()) {
  3922. photo->setWaitingForAlbum();
  3923. } else if (const auto document = media->document()) {
  3924. document->setWaitingForAlbum();
  3925. }
  3926. }
  3927. switch (result.type()) {
  3928. case mtpc_messageMediaPhoto: {
  3929. const auto &data = result.c_messageMediaPhoto();
  3930. const auto photo = data.vphoto();
  3931. if (!photo || photo->type() != mtpc_photo) {
  3932. failed();
  3933. return;
  3934. }
  3935. const auto &fields = photo->c_photo();
  3936. using Flag = MTPDinputMediaPhoto::Flag;
  3937. const auto flags = Flag()
  3938. | (data.vttl_seconds() ? Flag::f_ttl_seconds : Flag())
  3939. | (spoiler ? Flag::f_spoiler : Flag());
  3940. const auto media = MTP_inputMediaPhoto(
  3941. MTP_flags(flags),
  3942. MTP_inputPhoto(
  3943. fields.vid(),
  3944. fields.vaccess_hash(),
  3945. fields.vfile_reference()),
  3946. MTP_int(data.vttl_seconds().value_or_empty()));
  3947. sendAlbumWithUploaded(item, groupId, media);
  3948. } break;
  3949. case mtpc_messageMediaDocument: {
  3950. const auto &data = result.c_messageMediaDocument();
  3951. const auto document = data.vdocument();
  3952. if (!document || document->type() != mtpc_document) {
  3953. failed();
  3954. return;
  3955. }
  3956. const auto &fields = document->c_document();
  3957. const auto mtpCover = data.vvideo_cover();
  3958. const auto cover = (mtpCover && mtpCover->type() == mtpc_photo)
  3959. ? &(mtpCover->c_photo())
  3960. : (const MTPDphoto*)nullptr;
  3961. using Flag = MTPDinputMediaDocument::Flag;
  3962. const auto flags = Flag()
  3963. | (data.vttl_seconds() ? Flag::f_ttl_seconds : Flag())
  3964. | (spoiler ? Flag::f_spoiler : Flag())
  3965. | (data.vvideo_timestamp() ? Flag::f_video_timestamp : Flag())
  3966. | (cover ? Flag::f_video_cover : Flag());
  3967. const auto media = MTP_inputMediaDocument(
  3968. MTP_flags(flags),
  3969. MTP_inputDocument(
  3970. fields.vid(),
  3971. fields.vaccess_hash(),
  3972. fields.vfile_reference()),
  3973. (cover
  3974. ? MTP_inputPhoto(
  3975. cover->vid(),
  3976. cover->vaccess_hash(),
  3977. cover->vfile_reference())
  3978. : MTPInputPhoto()),
  3979. MTP_int(data.vvideo_timestamp().value_or_empty()),
  3980. MTP_int(data.vttl_seconds().value_or_empty()),
  3981. MTPstring()); // query
  3982. sendAlbumWithUploaded(item, groupId, media);
  3983. } break;
  3984. }
  3985. }).fail([=] {
  3986. failed();
  3987. }).send();
  3988. }
  3989. void ApiWrap::sendMedia(
  3990. not_null<HistoryItem*> item,
  3991. const MTPInputMedia &media,
  3992. Api::SendOptions options,
  3993. Fn<void(bool)> done) {
  3994. const auto randomId = base::RandomValue<uint64>();
  3995. _session->data().registerMessageRandomId(randomId, item->fullId());
  3996. sendMediaWithRandomId(item, media, options, randomId, std::move(done));
  3997. }
  3998. void ApiWrap::sendMediaWithRandomId(
  3999. not_null<HistoryItem*> item,
  4000. const MTPInputMedia &media,
  4001. Api::SendOptions options,
  4002. uint64 randomId,
  4003. Fn<void(bool)> done) {
  4004. const auto history = item->history();
  4005. const auto replyTo = item->replyTo();
  4006. const auto peer = history->peer;
  4007. auto caption = item->originalText();
  4008. TextUtilities::Trim(caption);
  4009. auto sentEntities = Api::EntitiesToMTP(
  4010. _session,
  4011. caption.entities,
  4012. Api::ConvertOption::SkipLocal);
  4013. const auto updateRecentStickers = Api::HasAttachedStickers(media);
  4014. const auto starsPaid = std::min(
  4015. peer->starsPerMessageChecked(),
  4016. options.starsApproved);
  4017. if (starsPaid) {
  4018. options.starsApproved -= starsPaid;
  4019. }
  4020. using Flag = MTPmessages_SendMedia::Flag;
  4021. const auto flags = Flag(0)
  4022. | (replyTo ? Flag::f_reply_to : Flag(0))
  4023. | (ShouldSendSilent(history->peer, options)
  4024. ? Flag::f_silent
  4025. : Flag(0))
  4026. | (!sentEntities.v.isEmpty() ? Flag::f_entities : Flag(0))
  4027. | (options.scheduled ? Flag::f_schedule_date : Flag(0))
  4028. | (options.sendAs ? Flag::f_send_as : Flag(0))
  4029. | (options.shortcutId ? Flag::f_quick_reply_shortcut : Flag(0))
  4030. | (options.effectId ? Flag::f_effect : Flag(0))
  4031. | (options.invertCaption ? Flag::f_invert_media : Flag(0))
  4032. | (starsPaid ? Flag::f_allow_paid_stars : Flag(0));
  4033. auto &histories = history->owner().histories();
  4034. const auto itemId = item->fullId();
  4035. histories.sendPreparedMessage(
  4036. history,
  4037. replyTo,
  4038. randomId,
  4039. Data::Histories::PrepareMessage<MTPmessages_SendMedia>(
  4040. MTP_flags(flags),
  4041. peer->input,
  4042. Data::Histories::ReplyToPlaceholder(),
  4043. (options.price
  4044. ? MTPInputMedia(MTP_inputMediaPaidMedia(
  4045. MTP_flags(0),
  4046. MTP_long(options.price),
  4047. MTP_vector<MTPInputMedia>(1, media),
  4048. MTPstring()))
  4049. : media),
  4050. MTP_string(caption.text),
  4051. MTP_long(randomId),
  4052. MTPReplyMarkup(),
  4053. sentEntities,
  4054. MTP_int(options.scheduled),
  4055. (options.sendAs ? options.sendAs->input : MTP_inputPeerEmpty()),
  4056. Data::ShortcutIdToMTP(_session, options.shortcutId),
  4057. MTP_long(options.effectId),
  4058. MTP_long(starsPaid)
  4059. ), [=](const MTPUpdates &result, const MTP::Response &response) {
  4060. if (done) done(true);
  4061. if (updateRecentStickers) {
  4062. requestRecentStickers(std::nullopt, true);
  4063. }
  4064. }, [=](const MTP::Error &error, const MTP::Response &response) {
  4065. if (done) done(false);
  4066. sendMessageFail(error, peer, randomId, itemId);
  4067. });
  4068. }
  4069. void ApiWrap::sendMultiPaidMedia(
  4070. not_null<HistoryItem*> item,
  4071. not_null<SendingAlbum*> album,
  4072. Fn<void(bool)> done) {
  4073. Expects(album->options.price > 0);
  4074. const auto groupId = album->groupId;
  4075. auto &options = album->options;
  4076. const auto randomId = album->items.front().randomId;
  4077. auto medias = album->items | ranges::view::transform([](
  4078. const SendingAlbum::Item &part) {
  4079. Assert(part.media.has_value());
  4080. return MTPInputMedia(part.media->data().vmedia());
  4081. }) | ranges::to<QVector<MTPInputMedia>>();
  4082. const auto history = item->history();
  4083. const auto replyTo = item->replyTo();
  4084. const auto peer = history->peer;
  4085. auto caption = item->originalText();
  4086. TextUtilities::Trim(caption);
  4087. auto sentEntities = Api::EntitiesToMTP(
  4088. _session,
  4089. caption.entities,
  4090. Api::ConvertOption::SkipLocal);
  4091. const auto starsPaid = std::min(
  4092. peer->starsPerMessageChecked(),
  4093. options.starsApproved);
  4094. if (starsPaid) {
  4095. options.starsApproved -= starsPaid;
  4096. }
  4097. using Flag = MTPmessages_SendMedia::Flag;
  4098. const auto flags = Flag(0)
  4099. | (replyTo ? Flag::f_reply_to : Flag(0))
  4100. | (ShouldSendSilent(history->peer, options)
  4101. ? Flag::f_silent
  4102. : Flag(0))
  4103. | (!sentEntities.v.isEmpty() ? Flag::f_entities : Flag(0))
  4104. | (options.scheduled ? Flag::f_schedule_date : Flag(0))
  4105. | (options.sendAs ? Flag::f_send_as : Flag(0))
  4106. | (options.shortcutId ? Flag::f_quick_reply_shortcut : Flag(0))
  4107. | (options.effectId ? Flag::f_effect : Flag(0))
  4108. | (options.invertCaption ? Flag::f_invert_media : Flag(0))
  4109. | (starsPaid ? Flag::f_allow_paid_stars : Flag(0));
  4110. auto &histories = history->owner().histories();
  4111. const auto itemId = item->fullId();
  4112. album->sent = true;
  4113. histories.sendPreparedMessage(
  4114. history,
  4115. replyTo,
  4116. randomId,
  4117. Data::Histories::PrepareMessage<MTPmessages_SendMedia>(
  4118. MTP_flags(flags),
  4119. peer->input,
  4120. Data::Histories::ReplyToPlaceholder(),
  4121. MTP_inputMediaPaidMedia(
  4122. MTP_flags(0),
  4123. MTP_long(options.price),
  4124. MTP_vector<MTPInputMedia>(std::move(medias)),
  4125. MTPstring()),
  4126. MTP_string(caption.text),
  4127. MTP_long(randomId),
  4128. MTPReplyMarkup(),
  4129. sentEntities,
  4130. MTP_int(options.scheduled),
  4131. (options.sendAs ? options.sendAs->input : MTP_inputPeerEmpty()),
  4132. Data::ShortcutIdToMTP(_session, options.shortcutId),
  4133. MTP_long(options.effectId),
  4134. MTP_long(starsPaid)
  4135. ), [=](const MTPUpdates &result, const MTP::Response &response) {
  4136. if (const auto album = _sendingAlbums.take(groupId)) {
  4137. const auto copy = (*album)->items;
  4138. for (const auto &part : copy) {
  4139. if (const auto item = history->owner().message(part.msgId)) {
  4140. item->destroy();
  4141. }
  4142. }
  4143. }
  4144. if (done) done(true);
  4145. }, [=](const MTP::Error &error, const MTP::Response &response) {
  4146. if (done) done(false);
  4147. sendMessageFail(error, peer, randomId, itemId);
  4148. });
  4149. }
  4150. void ApiWrap::sendAlbumWithUploaded(
  4151. not_null<HistoryItem*> item,
  4152. const MessageGroupId &groupId,
  4153. const MTPInputMedia &media) {
  4154. const auto localId = item->fullId();
  4155. const auto randomId = base::RandomValue<uint64>();
  4156. _session->data().registerMessageRandomId(randomId, localId);
  4157. const auto albumIt = _sendingAlbums.find(groupId.raw());
  4158. Assert(albumIt != _sendingAlbums.end());
  4159. const auto &album = albumIt->second;
  4160. album->fillMedia(item, media, randomId);
  4161. sendAlbumIfReady(album.get());
  4162. }
  4163. void ApiWrap::sendAlbumWithCancelled(
  4164. not_null<HistoryItem*> item,
  4165. const MessageGroupId &groupId) {
  4166. const auto albumIt = _sendingAlbums.find(groupId.raw());
  4167. if (albumIt == _sendingAlbums.end()) {
  4168. // Sometimes we destroy item being sent already after the album
  4169. // was sent successfully. For example the message could be loaded
  4170. // from server (by messages.getHistory or updateNewMessage) and
  4171. // added to history and after that updateMessageID was received with
  4172. // the same message id, in this case we destroy a detached local
  4173. // item and sendAlbumWithCancelled is called for already sent album.
  4174. return;
  4175. }
  4176. const auto &album = albumIt->second;
  4177. album->removeItem(item);
  4178. sendAlbumIfReady(album.get());
  4179. }
  4180. void ApiWrap::sendAlbumIfReady(not_null<SendingAlbum*> album) {
  4181. if (album->sent) {
  4182. return;
  4183. }
  4184. const auto groupId = album->groupId;
  4185. if (album->items.empty()) {
  4186. _sendingAlbums.remove(groupId);
  4187. return;
  4188. }
  4189. auto sample = (HistoryItem*)nullptr;
  4190. auto medias = QVector<MTPInputSingleMedia>();
  4191. medias.reserve(album->items.size());
  4192. for (const auto &item : album->items) {
  4193. if (!item.media) {
  4194. return;
  4195. } else if (!sample) {
  4196. sample = _session->data().message(item.msgId);
  4197. }
  4198. medias.push_back(*item.media);
  4199. }
  4200. if (!sample) {
  4201. _sendingAlbums.remove(groupId);
  4202. return;
  4203. } else if (album->options.price > 0) {
  4204. sendMultiPaidMedia(sample, album);
  4205. return;
  4206. } else if (medias.size() < 2) {
  4207. const auto &single = medias.front().data();
  4208. album->sent = true;
  4209. sendMediaWithRandomId(
  4210. sample,
  4211. single.vmedia(),
  4212. album->options,
  4213. single.vrandom_id().v);
  4214. _sendingAlbums.remove(groupId);
  4215. return;
  4216. }
  4217. const auto history = sample->history();
  4218. const auto replyTo = sample->replyTo();
  4219. const auto sendAs = album->options.sendAs;
  4220. const auto starsPaid = std::min(
  4221. history->peer->starsPerMessageChecked() * int(medias.size()),
  4222. album->options.starsApproved);
  4223. if (starsPaid) {
  4224. album->options.starsApproved -= starsPaid;
  4225. }
  4226. using Flag = MTPmessages_SendMultiMedia::Flag;
  4227. const auto flags = Flag(0)
  4228. | (replyTo ? Flag::f_reply_to : Flag(0))
  4229. | (ShouldSendSilent(history->peer, album->options)
  4230. ? Flag::f_silent
  4231. : Flag(0))
  4232. | (album->options.scheduled ? Flag::f_schedule_date : Flag(0))
  4233. | (sendAs ? Flag::f_send_as : Flag(0))
  4234. | (album->options.shortcutId
  4235. ? Flag::f_quick_reply_shortcut
  4236. : Flag(0))
  4237. | (album->options.effectId ? Flag::f_effect : Flag(0))
  4238. | (album->options.invertCaption ? Flag::f_invert_media : Flag(0))
  4239. | (starsPaid ? Flag::f_allow_paid_stars : Flag(0));
  4240. auto &histories = history->owner().histories();
  4241. const auto peer = history->peer;
  4242. album->sent = true;
  4243. histories.sendPreparedMessage(
  4244. history,
  4245. replyTo,
  4246. uint64(0), // randomId
  4247. Data::Histories::PrepareMessage<MTPmessages_SendMultiMedia>(
  4248. MTP_flags(flags),
  4249. peer->input,
  4250. Data::Histories::ReplyToPlaceholder(),
  4251. MTP_vector<MTPInputSingleMedia>(medias),
  4252. MTP_int(album->options.scheduled),
  4253. (sendAs ? sendAs->input : MTP_inputPeerEmpty()),
  4254. Data::ShortcutIdToMTP(_session, album->options.shortcutId),
  4255. MTP_long(album->options.effectId),
  4256. MTP_long(starsPaid)
  4257. ), [=](const MTPUpdates &result, const MTP::Response &response) {
  4258. _sendingAlbums.remove(groupId);
  4259. }, [=](const MTP::Error &error, const MTP::Response &response) {
  4260. if (const auto album = _sendingAlbums.take(groupId)) {
  4261. for (const auto &item : (*album)->items) {
  4262. sendMessageFail(error, peer, item.randomId, item.msgId);
  4263. }
  4264. } else {
  4265. sendMessageFail(error, peer);
  4266. }
  4267. });
  4268. }
  4269. void ApiWrap::reloadContactSignupSilent() {
  4270. if (_contactSignupSilentRequestId) {
  4271. return;
  4272. }
  4273. const auto requestId = request(MTPaccount_GetContactSignUpNotification(
  4274. )).done([=](const MTPBool &result) {
  4275. _contactSignupSilentRequestId = 0;
  4276. const auto silent = mtpIsTrue(result);
  4277. _contactSignupSilent = silent;
  4278. _contactSignupSilentChanges.fire_copy(silent);
  4279. }).fail([=] {
  4280. _contactSignupSilentRequestId = 0;
  4281. }).send();
  4282. _contactSignupSilentRequestId = requestId;
  4283. }
  4284. rpl::producer<bool> ApiWrap::contactSignupSilent() const {
  4285. return _contactSignupSilent
  4286. ? _contactSignupSilentChanges.events_starting_with_copy(
  4287. *_contactSignupSilent)
  4288. : (_contactSignupSilentChanges.events() | rpl::type_erased());
  4289. }
  4290. std::optional<bool> ApiWrap::contactSignupSilentCurrent() const {
  4291. return _contactSignupSilent;
  4292. }
  4293. void ApiWrap::saveContactSignupSilent(bool silent) {
  4294. request(base::take(_contactSignupSilentRequestId)).cancel();
  4295. const auto requestId = request(MTPaccount_SetContactSignUpNotification(
  4296. MTP_bool(silent)
  4297. )).done([=] {
  4298. _contactSignupSilentRequestId = 0;
  4299. _contactSignupSilent = silent;
  4300. _contactSignupSilentChanges.fire_copy(silent);
  4301. }).fail([=] {
  4302. _contactSignupSilentRequestId = 0;
  4303. }).send();
  4304. _contactSignupSilentRequestId = requestId;
  4305. }
  4306. auto ApiWrap::botCommonGroups(not_null<UserData*> bot) const
  4307. -> std::optional<std::vector<not_null<PeerData*>>> {
  4308. const auto i = _botCommonGroups.find(bot);
  4309. return (i != end(_botCommonGroups))
  4310. ? i->second
  4311. : std::optional<std::vector<not_null<PeerData*>>>();
  4312. }
  4313. void ApiWrap::requestBotCommonGroups(
  4314. not_null<UserData*> bot,
  4315. Fn<void()> done) {
  4316. if (_botCommonGroupsRequests.contains(bot)) {
  4317. return;
  4318. }
  4319. _botCommonGroupsRequests.emplace(bot, done);
  4320. const auto finish = [=](std::vector<not_null<PeerData*>> list) {
  4321. _botCommonGroups.emplace(bot, std::move(list));
  4322. if (const auto callback = _botCommonGroupsRequests.take(bot)) {
  4323. (*callback)();
  4324. }
  4325. };
  4326. const auto limit = 100;
  4327. request(MTPmessages_GetCommonChats(
  4328. bot->inputUser,
  4329. MTP_long(0), // max_id
  4330. MTP_int(limit)
  4331. )).done([=](const MTPmessages_Chats &result) {
  4332. const auto chats = result.match([](const auto &data) {
  4333. return &data.vchats().v;
  4334. });
  4335. auto &owner = session().data();
  4336. auto list = std::vector<not_null<PeerData*>>();
  4337. list.reserve(chats->size());
  4338. for (const auto &chat : *chats) {
  4339. if (const auto peer = owner.processChat(chat)) {
  4340. list.push_back(peer);
  4341. }
  4342. }
  4343. finish(std::move(list));
  4344. }).fail([=] {
  4345. finish({});
  4346. }).send();
  4347. }
  4348. void ApiWrap::saveSelfBio(const QString &text) {
  4349. if (_bio.requestId) {
  4350. if (text != _bio.requestedText) {
  4351. request(_bio.requestId).cancel();
  4352. } else {
  4353. return;
  4354. }
  4355. }
  4356. _bio.requestedText = text;
  4357. _bio.requestId = request(MTPaccount_UpdateProfile(
  4358. MTP_flags(MTPaccount_UpdateProfile::Flag::f_about),
  4359. MTPstring(),
  4360. MTPstring(),
  4361. MTP_string(text)
  4362. )).done([=](const MTPUser &result) {
  4363. _bio.requestId = 0;
  4364. _session->data().processUser(result);
  4365. _session->user()->setAbout(_bio.requestedText);
  4366. }).fail([=] {
  4367. _bio.requestId = 0;
  4368. }).send();
  4369. }
  4370. void ApiWrap::registerStatsRequest(MTP::DcId dcId, mtpRequestId id) {
  4371. _statsRequests[dcId].emplace(id);
  4372. }
  4373. void ApiWrap::unregisterStatsRequest(MTP::DcId dcId, mtpRequestId id) {
  4374. const auto i = _statsRequests.find(dcId);
  4375. Assert(i != end(_statsRequests));
  4376. const auto removed = i->second.remove(id);
  4377. Assert(removed);
  4378. if (i->second.empty()) {
  4379. _statsSessionKillTimer.callOnce(kStatsSessionKillTimeout);
  4380. }
  4381. }
  4382. void ApiWrap::checkStatsSessions() {
  4383. for (auto i = begin(_statsRequests); i != end(_statsRequests);) {
  4384. if (i->second.empty()) {
  4385. instance().killSession(
  4386. MTP::ShiftDcId(i->first, MTP::kStatsDcShift));
  4387. i = _statsRequests.erase(i);
  4388. } else {
  4389. ++i;
  4390. }
  4391. }
  4392. }
  4393. Api::Authorizations &ApiWrap::authorizations() {
  4394. return *_authorizations;
  4395. }
  4396. Api::AttachedStickers &ApiWrap::attachedStickers() {
  4397. return *_attachedStickers;
  4398. }
  4399. Api::BlockedPeers &ApiWrap::blockedPeers() {
  4400. return *_blockedPeers;
  4401. }
  4402. Api::CloudPassword &ApiWrap::cloudPassword() {
  4403. return *_cloudPassword;
  4404. }
  4405. Api::SelfDestruct &ApiWrap::selfDestruct() {
  4406. return *_selfDestruct;
  4407. }
  4408. Api::SensitiveContent &ApiWrap::sensitiveContent() {
  4409. return *_sensitiveContent;
  4410. }
  4411. Api::GlobalPrivacy &ApiWrap::globalPrivacy() {
  4412. return *_globalPrivacy;
  4413. }
  4414. Api::UserPrivacy &ApiWrap::userPrivacy() {
  4415. return *_userPrivacy;
  4416. }
  4417. Api::InviteLinks &ApiWrap::inviteLinks() {
  4418. return *_inviteLinks;
  4419. }
  4420. Api::ChatLinks &ApiWrap::chatLinks() {
  4421. return *_chatLinks;
  4422. }
  4423. Api::ViewsManager &ApiWrap::views() {
  4424. return *_views;
  4425. }
  4426. Api::ConfirmPhone &ApiWrap::confirmPhone() {
  4427. return *_confirmPhone;
  4428. }
  4429. Api::PeerPhoto &ApiWrap::peerPhoto() {
  4430. return *_peerPhoto;
  4431. }
  4432. Api::Polls &ApiWrap::polls() {
  4433. return *_polls;
  4434. }
  4435. Api::ChatParticipants &ApiWrap::chatParticipants() {
  4436. return *_chatParticipants;
  4437. }
  4438. Api::UnreadThings &ApiWrap::unreadThings() {
  4439. return *_unreadThings;
  4440. }
  4441. Api::Ringtones &ApiWrap::ringtones() {
  4442. return *_ringtones;
  4443. }
  4444. Api::Transcribes &ApiWrap::transcribes() {
  4445. return *_transcribes;
  4446. }
  4447. Api::Premium &ApiWrap::premium() {
  4448. return *_premium;
  4449. }
  4450. Api::Usernames &ApiWrap::usernames() {
  4451. return *_usernames;
  4452. }
  4453. Api::Websites &ApiWrap::websites() {
  4454. return *_websites;
  4455. }
  4456. Api::PeerColors &ApiWrap::peerColors() {
  4457. return *_peerColors;
  4458. }