serialize_peer.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487
  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 "storage/serialize_peer.h"
  8. #include "storage/serialize_common.h"
  9. #include "main/main_session.h"
  10. #include "data/data_channel.h"
  11. #include "data/data_chat.h"
  12. #include "data/data_user.h"
  13. #include "data/data_session.h"
  14. #include "ui/image/image.h"
  15. #include "ui/text/format_values.h" // Ui::FormatPhone
  16. namespace Serialize {
  17. namespace {
  18. constexpr auto kModernImageLocationTag = std::numeric_limits<qint32>::min();
  19. constexpr auto kVersionTag = uint64(0x77FF'FFFF'FFFF'FFFFULL);
  20. constexpr auto kVersion = 2;
  21. } // namespace
  22. std::optional<StorageImageLocation> readLegacyStorageImageLocationOrTag(
  23. int streamAppVersion,
  24. QDataStream &stream) {
  25. qint32 width, height, dc, local;
  26. quint64 volume, secret;
  27. QByteArray fileReference;
  28. stream >> width;
  29. if (width == kModernImageLocationTag) {
  30. return std::nullopt;
  31. }
  32. stream >> height >> dc >> volume >> local >> secret;
  33. if (streamAppVersion >= 1003013) {
  34. stream >> fileReference;
  35. }
  36. if (stream.status() != QDataStream::Ok) {
  37. return std::nullopt;
  38. }
  39. return StorageImageLocation(
  40. StorageFileLocation(
  41. dc,
  42. UserId(0), // self
  43. MTP_inputFileLocation(
  44. MTP_long(volume),
  45. MTP_int(local),
  46. MTP_long(secret),
  47. MTP_bytes(fileReference))),
  48. width,
  49. height);
  50. }
  51. int storageImageLocationSize(const StorageImageLocation &location) {
  52. // Modern image location tag + (size + content) of the serialization.
  53. return sizeof(qint32) * 2 + location.serializeSize();
  54. }
  55. void writeStorageImageLocation(
  56. QDataStream &stream,
  57. const StorageImageLocation &location) {
  58. stream << kModernImageLocationTag << location.serialize();
  59. }
  60. std::optional<StorageImageLocation> readStorageImageLocation(
  61. int streamAppVersion,
  62. QDataStream &stream) {
  63. const auto legacy = readLegacyStorageImageLocationOrTag(
  64. streamAppVersion,
  65. stream);
  66. if (legacy) {
  67. return legacy;
  68. }
  69. auto serialized = QByteArray();
  70. stream >> serialized;
  71. return (stream.status() == QDataStream::Ok)
  72. ? StorageImageLocation::FromSerialized(serialized)
  73. : std::nullopt;
  74. }
  75. int imageLocationSize(const ImageLocation &location) {
  76. // Modern image location tag + (size + content) of the serialization.
  77. return sizeof(qint32) * 2 + location.serializeSize();
  78. }
  79. void writeImageLocation(QDataStream &stream, const ImageLocation &location) {
  80. stream << kModernImageLocationTag << location.serialize();
  81. }
  82. std::optional<ImageLocation> readImageLocation(
  83. int streamAppVersion,
  84. QDataStream &stream) {
  85. const auto legacy = readLegacyStorageImageLocationOrTag(
  86. streamAppVersion,
  87. stream);
  88. if (legacy) {
  89. return ImageLocation(
  90. DownloadLocation{ legacy->file() },
  91. legacy->width(),
  92. legacy->height());
  93. }
  94. auto serialized = QByteArray();
  95. stream >> serialized;
  96. return (stream.status() == QDataStream::Ok)
  97. ? ImageLocation::FromSerialized(serialized)
  98. : std::nullopt;
  99. }
  100. uint32 peerSize(not_null<PeerData*> peer) {
  101. uint32 result = sizeof(quint64) // id
  102. + sizeof(quint64) // version tag
  103. + sizeof(qint32) // version
  104. + sizeof(quint64) // userpic photo id
  105. + imageLocationSize(peer->userpicLocation())
  106. + sizeof(qint32); // userpic has video
  107. if (const auto user = peer->asUser()) {
  108. const auto botInlinePlaceholder = user->isBot()
  109. ? user->botInfo->inlinePlaceholder
  110. : QString();
  111. result += stringSize(user->firstName)
  112. + stringSize(user->lastName)
  113. + stringSize(user->phone())
  114. + stringSize(user->username())
  115. + sizeof(quint64) // access
  116. + sizeof(qint32) // flags
  117. + stringSize(botInlinePlaceholder)
  118. + sizeof(quint32) // lastseen
  119. + sizeof(qint32) // contact
  120. + sizeof(qint32); // botInfoVersion
  121. } else if (const auto chat = peer->asChat()) {
  122. result += stringSize(chat->name())
  123. + sizeof(qint32) // count
  124. + sizeof(qint32) // date
  125. + sizeof(qint32) // version
  126. + sizeof(qint32) // creator id 1
  127. + sizeof(qint32) // creator id 2
  128. + sizeof(quint32) // flags
  129. + stringSize(chat->inviteLink());
  130. } else if (const auto channel = peer->asChannel()) {
  131. result += stringSize(channel->name())
  132. + sizeof(quint64) // access
  133. + sizeof(qint32) // date
  134. + sizeof(qint32) // version
  135. + sizeof(qint32) // old forbidden
  136. + sizeof(quint32) // flags
  137. + stringSize(channel->inviteLink());
  138. }
  139. return result;
  140. }
  141. void writePeer(QDataStream &stream, not_null<PeerData*> peer) {
  142. stream
  143. << SerializePeerId(peer->id)
  144. << quint64(kVersionTag)
  145. << qint32(kVersion)
  146. << quint64(peer->userpicPhotoId());
  147. writeImageLocation(stream, peer->userpicLocation());
  148. stream << qint32(peer->userpicHasVideo() ? 1 : 0);
  149. if (const auto user = peer->asUser()) {
  150. const auto botInlinePlaceholder = user->isBot()
  151. ? user->botInfo->inlinePlaceholder
  152. : QString();
  153. stream
  154. << user->firstName
  155. << user->lastName
  156. << user->phone()
  157. << user->username()
  158. << quint64(user->accessHash())
  159. << qint32(user->flags())
  160. << botInlinePlaceholder
  161. << quint32(user->lastseen().serialize())
  162. << qint32(user->isContact() ? 1 : 0)
  163. << qint32(user->isBot() ? user->botInfo->version : -1);
  164. } else if (const auto chat = peer->asChat()) {
  165. auto field1 = qint32(uint32(chat->creator.bare & 0xFFFFFFFFULL));
  166. auto field2 = qint32(uint32(chat->creator.bare >> 32) << 8);
  167. stream
  168. << chat->name()
  169. << qint32(chat->count)
  170. << qint32(chat->date)
  171. << qint32(chat->version())
  172. << field1
  173. << field2
  174. << quint32(chat->flags())
  175. << chat->inviteLink();
  176. } else if (const auto channel = peer->asChannel()) {
  177. stream
  178. << channel->name()
  179. << quint64(channel->access)
  180. << qint32(channel->date)
  181. << qint32(0) // legacy - version
  182. << qint32(0)
  183. << quint32(channel->flags())
  184. << channel->inviteLink();
  185. }
  186. }
  187. PeerData *readPeer(
  188. not_null<Main::Session*> session,
  189. int streamAppVersion,
  190. QDataStream &stream) {
  191. quint64 peerIdSerialized = 0, versionTag = 0, photoId = 0;
  192. qint32 version = 0, photoHasVideo = 0;
  193. stream >> peerIdSerialized >> versionTag;
  194. const auto peerId = DeserializePeerId(peerIdSerialized);
  195. if (!peerId) {
  196. return nullptr;
  197. }
  198. if (versionTag == kVersionTag) {
  199. stream >> version >> photoId;
  200. } else {
  201. photoId = versionTag;
  202. }
  203. const auto userpic = readImageLocation(streamAppVersion, stream);
  204. auto userpicAccessHash = uint64(0);
  205. if (!userpic) {
  206. return nullptr;
  207. }
  208. if (version > 0) {
  209. stream >> photoHasVideo;
  210. }
  211. const auto selfId = session->userPeerId();
  212. const auto loaded = (peerId == selfId)
  213. ? session->user().get()
  214. : session->data().peerLoaded(peerId);
  215. const auto apply = !loaded || !loaded->isLoaded();
  216. const auto result = loaded ? loaded : session->data().peer(peerId).get();
  217. if (apply) {
  218. result->setLoadedStatus(PeerData::LoadedStatus::Normal);
  219. }
  220. if (const auto user = result->asUser()) {
  221. QString first, last, phone, username, inlinePlaceholder;
  222. quint64 access;
  223. qint32 flags = 0, contact, botInfoVersion;
  224. quint32 lastseen;
  225. stream >> first >> last >> phone >> username >> access;
  226. if (streamAppVersion >= 9012) {
  227. stream >> flags;
  228. }
  229. if (streamAppVersion >= 9016) {
  230. stream >> inlinePlaceholder;
  231. }
  232. stream >> lastseen >> contact >> botInfoVersion;
  233. userpicAccessHash = access;
  234. if (apply) {
  235. const auto showPhone = !user->isServiceUser()
  236. && (user->id != selfId)
  237. && (contact <= 0);
  238. const auto pname = (showPhone && !phone.isEmpty())
  239. ? Ui::FormatPhone(phone)
  240. : QString();
  241. user->setPhone(phone);
  242. user->setName(first, last, pname, username);
  243. if (streamAppVersion >= 2008007) {
  244. user->setFlags(UserDataFlags::from_raw(flags));
  245. } else {
  246. using Saved = MTPDuser::Flag;
  247. using Flag = UserDataFlag;
  248. struct Conversion {
  249. Saved saved;
  250. Flag flag;
  251. };
  252. const auto conversions = {
  253. Conversion{ Saved::f_deleted, Flag::Deleted },
  254. Conversion{ Saved::f_verified, Flag::Verified },
  255. Conversion{ Saved::f_scam, Flag::Scam },
  256. Conversion{ Saved::f_fake, Flag::Fake },
  257. Conversion{ Saved::f_bot_inline_geo, Flag::BotInlineGeo },
  258. Conversion{ Saved::f_support, Flag::Support },
  259. Conversion{ Saved::f_contact, Flag::Contact },
  260. Conversion{ Saved::f_mutual_contact, Flag::MutualContact },
  261. };
  262. auto flagsMask = Flag() | Flag();
  263. auto flagsSet = Flag() | Flag();
  264. for (const auto &conversion : conversions) {
  265. flagsMask |= conversion.flag;
  266. if (flags & int(conversion.saved)) {
  267. flagsSet |= conversion.flag;
  268. }
  269. }
  270. user->setFlags((user->flags() & ~flagsMask) | flagsSet);
  271. }
  272. user->setAccessHash(access);
  273. user->updateLastseen((version > 1)
  274. ? Data::LastseenStatus::FromSerialized(lastseen)
  275. : Data::LastseenStatus::FromLegacy(lastseen));
  276. user->setIsContact(contact == 1);
  277. user->setBotInfoVersion(botInfoVersion);
  278. if (!inlinePlaceholder.isEmpty() && user->isBot()) {
  279. user->botInfo->inlinePlaceholder = inlinePlaceholder;
  280. }
  281. if (user->id == selfId) {
  282. user->input = MTP_inputPeerSelf();
  283. user->inputUser = MTP_inputUserSelf();
  284. } else {
  285. user->input = MTP_inputPeerUser(MTP_long(peerToUser(user->id).bare), MTP_long(user->accessHash()));
  286. user->inputUser = MTP_inputUser(MTP_long(peerToUser(user->id).bare), MTP_long(user->accessHash()));
  287. }
  288. }
  289. } else if (const auto chat = result->asChat()) {
  290. QString name, inviteLink;
  291. qint32 count, date, version, field1, field2;
  292. quint32 flags;
  293. stream
  294. >> name
  295. >> count
  296. >> date
  297. >> version
  298. >> field1
  299. >> field2
  300. >> flags
  301. >> inviteLink;
  302. if (apply) {
  303. const auto creator = UserId(
  304. BareId(uint32(field1)) | (BareId(uint32(field2) >> 8) << 32));
  305. chat->setName(name);
  306. chat->count = count;
  307. chat->date = date;
  308. // We don't save participants, admin status and banned rights.
  309. // So we don't restore the version field, info is still unknown.
  310. chat->setVersion(0);
  311. if (streamAppVersion >= 2008007) {
  312. chat->setFlags(ChatDataFlags::from_raw(flags));
  313. } else {
  314. const auto oldForbidden = ((uint32(field2) & 0xFF) == 1);
  315. using Saved = MTPDchat::Flag;
  316. using Flag = ChatDataFlag;
  317. struct Conversion {
  318. Saved saved;
  319. Flag flag;
  320. };
  321. const auto conversions = {
  322. Conversion{ Saved::f_left, Flag::Left },
  323. Conversion{ Saved::f_creator, Flag::Creator },
  324. Conversion{ Saved::f_deactivated, Flag::Deactivated },
  325. Conversion{ Saved(1U << 31), Flag::Forbidden },
  326. Conversion{ Saved::f_call_active, Flag::CallActive },
  327. Conversion{ Saved::f_call_not_empty, Flag::CallNotEmpty },
  328. };
  329. auto flagsMask = Flag() | Flag();
  330. auto flagsSet = Flag() | Flag();
  331. if (streamAppVersion >= 9012) {
  332. for (const auto &conversion : conversions) {
  333. flagsMask |= conversion.flag;
  334. if (flags & int(conversion.saved)) {
  335. flagsSet |= conversion.flag;
  336. }
  337. }
  338. } else {
  339. // flags was haveLeft
  340. if (flags == 1) {
  341. flagsSet |= Flag::Left;
  342. }
  343. }
  344. if (oldForbidden) {
  345. flagsSet |= Flag::Forbidden;
  346. }
  347. chat->setFlags((chat->flags() & ~flagsMask) | flagsSet);
  348. }
  349. chat->creator = creator;
  350. chat->setInviteLink(inviteLink);
  351. chat->input = MTP_inputPeerChat(MTP_long(peerToChat(chat->id).bare));
  352. }
  353. } else if (const auto channel = result->asChannel()) {
  354. QString name, inviteLink;
  355. quint64 access;
  356. qint32 date, version, oldForbidden;
  357. quint32 flags;
  358. stream
  359. >> name
  360. >> access
  361. >> date
  362. >> version
  363. >> oldForbidden
  364. >> flags
  365. >> inviteLink;
  366. userpicAccessHash = access;
  367. if (apply) {
  368. channel->setName(name, QString());
  369. channel->access = access;
  370. channel->date = date;
  371. if (streamAppVersion >= 2008007) {
  372. channel->setFlags(ChannelDataFlags::from_raw(flags));
  373. } else {
  374. using Saved = MTPDchannel::Flag;
  375. using Flag = ChannelDataFlag;
  376. struct Conversion {
  377. Saved saved;
  378. Flag flag;
  379. };
  380. const auto conversions = {
  381. Conversion{ Saved::f_broadcast, Flag::Broadcast },
  382. Conversion{ Saved::f_verified, Flag::Verified},
  383. Conversion{ Saved::f_scam, Flag::Scam},
  384. Conversion{ Saved::f_fake, Flag::Fake},
  385. Conversion{ Saved::f_megagroup, Flag::Megagroup},
  386. Conversion{ Saved::f_gigagroup, Flag::Gigagroup},
  387. Conversion{ Saved::f_username, Flag::Username},
  388. Conversion{ Saved::f_signatures, Flag::Signatures},
  389. Conversion{ Saved::f_has_link, Flag::HasLink},
  390. Conversion{
  391. Saved::f_slowmode_enabled,
  392. Flag::SlowmodeEnabled },
  393. Conversion{ Saved::f_call_active, Flag::CallActive },
  394. Conversion{ Saved::f_call_not_empty, Flag::CallNotEmpty },
  395. Conversion{ Saved(1U << 31), Flag::Forbidden },
  396. Conversion{ Saved::f_left, Flag::Left },
  397. Conversion{ Saved::f_creator, Flag::Creator },
  398. };
  399. auto flagsMask = Flag() | Flag();
  400. auto flagsSet = Flag() | Flag();
  401. for (const auto &conversion : conversions) {
  402. flagsMask |= conversion.flag;
  403. if (flags & int(conversion.saved)) {
  404. flagsSet |= conversion.flag;
  405. }
  406. }
  407. if (oldForbidden) {
  408. flagsSet |= Flag::Forbidden;
  409. }
  410. channel->setFlags((channel->flags() & ~flagsMask) | flagsSet);
  411. }
  412. channel->setInviteLink(inviteLink);
  413. channel->input = MTP_inputPeerChannel(MTP_long(peerToChannel(channel->id).bare), MTP_long(access));
  414. channel->inputChannel = MTP_inputChannel(MTP_long(peerToChannel(channel->id).bare), MTP_long(access));
  415. }
  416. }
  417. if (apply) {
  418. const auto location = userpic->convertToModernPeerPhoto(
  419. result->id.value,
  420. userpicAccessHash,
  421. photoId);
  422. result->setUserpic(photoId, location, (photoHasVideo == 1));
  423. }
  424. return result;
  425. }
  426. QString peekUserPhone(int streamAppVersion, QDataStream &stream) {
  427. quint64 peerIdSerialized = 0, versionTag = 0, photoId = 0;
  428. qint32 version = 0, photoHasVideo = 0;
  429. stream >> peerIdSerialized >> versionTag;
  430. const auto peerId = DeserializePeerId(peerIdSerialized);
  431. DEBUG_LOG(("peekUserPhone.id: %1").arg(peerId.value));
  432. if (!peerId || !peerIsUser(peerId)) {
  433. return nullptr;
  434. }
  435. if (versionTag == kVersionTag) {
  436. stream >> version >> photoId;
  437. } else {
  438. photoId = versionTag;
  439. }
  440. if (!readImageLocation(streamAppVersion, stream)) {
  441. return nullptr;
  442. }
  443. if (version > 0) {
  444. stream >> photoHasVideo;
  445. }
  446. QString first, last, phone;
  447. stream >> first >> last >> phone;
  448. DEBUG_LOG(("peekUserPhone.data: %1 %2 %3"
  449. ).arg(first, last, phone));
  450. return phone;
  451. }
  452. } // namespace Serialize