| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487 |
- /*
- This file is part of Telegram Desktop,
- the official desktop application for the Telegram messaging service.
- For license and copyright information please follow this link:
- https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
- */
- #include "storage/serialize_peer.h"
- #include "storage/serialize_common.h"
- #include "main/main_session.h"
- #include "data/data_channel.h"
- #include "data/data_chat.h"
- #include "data/data_user.h"
- #include "data/data_session.h"
- #include "ui/image/image.h"
- #include "ui/text/format_values.h" // Ui::FormatPhone
- namespace Serialize {
- namespace {
- constexpr auto kModernImageLocationTag = std::numeric_limits<qint32>::min();
- constexpr auto kVersionTag = uint64(0x77FF'FFFF'FFFF'FFFFULL);
- constexpr auto kVersion = 2;
- } // namespace
- std::optional<StorageImageLocation> readLegacyStorageImageLocationOrTag(
- int streamAppVersion,
- QDataStream &stream) {
- qint32 width, height, dc, local;
- quint64 volume, secret;
- QByteArray fileReference;
- stream >> width;
- if (width == kModernImageLocationTag) {
- return std::nullopt;
- }
- stream >> height >> dc >> volume >> local >> secret;
- if (streamAppVersion >= 1003013) {
- stream >> fileReference;
- }
- if (stream.status() != QDataStream::Ok) {
- return std::nullopt;
- }
- return StorageImageLocation(
- StorageFileLocation(
- dc,
- UserId(0), // self
- MTP_inputFileLocation(
- MTP_long(volume),
- MTP_int(local),
- MTP_long(secret),
- MTP_bytes(fileReference))),
- width,
- height);
- }
- int storageImageLocationSize(const StorageImageLocation &location) {
- // Modern image location tag + (size + content) of the serialization.
- return sizeof(qint32) * 2 + location.serializeSize();
- }
- void writeStorageImageLocation(
- QDataStream &stream,
- const StorageImageLocation &location) {
- stream << kModernImageLocationTag << location.serialize();
- }
- std::optional<StorageImageLocation> readStorageImageLocation(
- int streamAppVersion,
- QDataStream &stream) {
- const auto legacy = readLegacyStorageImageLocationOrTag(
- streamAppVersion,
- stream);
- if (legacy) {
- return legacy;
- }
- auto serialized = QByteArray();
- stream >> serialized;
- return (stream.status() == QDataStream::Ok)
- ? StorageImageLocation::FromSerialized(serialized)
- : std::nullopt;
- }
- int imageLocationSize(const ImageLocation &location) {
- // Modern image location tag + (size + content) of the serialization.
- return sizeof(qint32) * 2 + location.serializeSize();
- }
- void writeImageLocation(QDataStream &stream, const ImageLocation &location) {
- stream << kModernImageLocationTag << location.serialize();
- }
- std::optional<ImageLocation> readImageLocation(
- int streamAppVersion,
- QDataStream &stream) {
- const auto legacy = readLegacyStorageImageLocationOrTag(
- streamAppVersion,
- stream);
- if (legacy) {
- return ImageLocation(
- DownloadLocation{ legacy->file() },
- legacy->width(),
- legacy->height());
- }
- auto serialized = QByteArray();
- stream >> serialized;
- return (stream.status() == QDataStream::Ok)
- ? ImageLocation::FromSerialized(serialized)
- : std::nullopt;
- }
- uint32 peerSize(not_null<PeerData*> peer) {
- uint32 result = sizeof(quint64) // id
- + sizeof(quint64) // version tag
- + sizeof(qint32) // version
- + sizeof(quint64) // userpic photo id
- + imageLocationSize(peer->userpicLocation())
- + sizeof(qint32); // userpic has video
- if (const auto user = peer->asUser()) {
- const auto botInlinePlaceholder = user->isBot()
- ? user->botInfo->inlinePlaceholder
- : QString();
- result += stringSize(user->firstName)
- + stringSize(user->lastName)
- + stringSize(user->phone())
- + stringSize(user->username())
- + sizeof(quint64) // access
- + sizeof(qint32) // flags
- + stringSize(botInlinePlaceholder)
- + sizeof(quint32) // lastseen
- + sizeof(qint32) // contact
- + sizeof(qint32); // botInfoVersion
- } else if (const auto chat = peer->asChat()) {
- result += stringSize(chat->name())
- + sizeof(qint32) // count
- + sizeof(qint32) // date
- + sizeof(qint32) // version
- + sizeof(qint32) // creator id 1
- + sizeof(qint32) // creator id 2
- + sizeof(quint32) // flags
- + stringSize(chat->inviteLink());
- } else if (const auto channel = peer->asChannel()) {
- result += stringSize(channel->name())
- + sizeof(quint64) // access
- + sizeof(qint32) // date
- + sizeof(qint32) // version
- + sizeof(qint32) // old forbidden
- + sizeof(quint32) // flags
- + stringSize(channel->inviteLink());
- }
- return result;
- }
- void writePeer(QDataStream &stream, not_null<PeerData*> peer) {
- stream
- << SerializePeerId(peer->id)
- << quint64(kVersionTag)
- << qint32(kVersion)
- << quint64(peer->userpicPhotoId());
- writeImageLocation(stream, peer->userpicLocation());
- stream << qint32(peer->userpicHasVideo() ? 1 : 0);
- if (const auto user = peer->asUser()) {
- const auto botInlinePlaceholder = user->isBot()
- ? user->botInfo->inlinePlaceholder
- : QString();
- stream
- << user->firstName
- << user->lastName
- << user->phone()
- << user->username()
- << quint64(user->accessHash())
- << qint32(user->flags())
- << botInlinePlaceholder
- << quint32(user->lastseen().serialize())
- << qint32(user->isContact() ? 1 : 0)
- << qint32(user->isBot() ? user->botInfo->version : -1);
- } else if (const auto chat = peer->asChat()) {
- auto field1 = qint32(uint32(chat->creator.bare & 0xFFFFFFFFULL));
- auto field2 = qint32(uint32(chat->creator.bare >> 32) << 8);
- stream
- << chat->name()
- << qint32(chat->count)
- << qint32(chat->date)
- << qint32(chat->version())
- << field1
- << field2
- << quint32(chat->flags())
- << chat->inviteLink();
- } else if (const auto channel = peer->asChannel()) {
- stream
- << channel->name()
- << quint64(channel->access)
- << qint32(channel->date)
- << qint32(0) // legacy - version
- << qint32(0)
- << quint32(channel->flags())
- << channel->inviteLink();
- }
- }
- PeerData *readPeer(
- not_null<Main::Session*> session,
- int streamAppVersion,
- QDataStream &stream) {
- quint64 peerIdSerialized = 0, versionTag = 0, photoId = 0;
- qint32 version = 0, photoHasVideo = 0;
- stream >> peerIdSerialized >> versionTag;
- const auto peerId = DeserializePeerId(peerIdSerialized);
- if (!peerId) {
- return nullptr;
- }
- if (versionTag == kVersionTag) {
- stream >> version >> photoId;
- } else {
- photoId = versionTag;
- }
- const auto userpic = readImageLocation(streamAppVersion, stream);
- auto userpicAccessHash = uint64(0);
- if (!userpic) {
- return nullptr;
- }
- if (version > 0) {
- stream >> photoHasVideo;
- }
- const auto selfId = session->userPeerId();
- const auto loaded = (peerId == selfId)
- ? session->user().get()
- : session->data().peerLoaded(peerId);
- const auto apply = !loaded || !loaded->isLoaded();
- const auto result = loaded ? loaded : session->data().peer(peerId).get();
- if (apply) {
- result->setLoadedStatus(PeerData::LoadedStatus::Normal);
- }
- if (const auto user = result->asUser()) {
- QString first, last, phone, username, inlinePlaceholder;
- quint64 access;
- qint32 flags = 0, contact, botInfoVersion;
- quint32 lastseen;
- stream >> first >> last >> phone >> username >> access;
- if (streamAppVersion >= 9012) {
- stream >> flags;
- }
- if (streamAppVersion >= 9016) {
- stream >> inlinePlaceholder;
- }
- stream >> lastseen >> contact >> botInfoVersion;
- userpicAccessHash = access;
- if (apply) {
- const auto showPhone = !user->isServiceUser()
- && (user->id != selfId)
- && (contact <= 0);
- const auto pname = (showPhone && !phone.isEmpty())
- ? Ui::FormatPhone(phone)
- : QString();
- user->setPhone(phone);
- user->setName(first, last, pname, username);
- if (streamAppVersion >= 2008007) {
- user->setFlags(UserDataFlags::from_raw(flags));
- } else {
- using Saved = MTPDuser::Flag;
- using Flag = UserDataFlag;
- struct Conversion {
- Saved saved;
- Flag flag;
- };
- const auto conversions = {
- Conversion{ Saved::f_deleted, Flag::Deleted },
- Conversion{ Saved::f_verified, Flag::Verified },
- Conversion{ Saved::f_scam, Flag::Scam },
- Conversion{ Saved::f_fake, Flag::Fake },
- Conversion{ Saved::f_bot_inline_geo, Flag::BotInlineGeo },
- Conversion{ Saved::f_support, Flag::Support },
- Conversion{ Saved::f_contact, Flag::Contact },
- Conversion{ Saved::f_mutual_contact, Flag::MutualContact },
- };
- auto flagsMask = Flag() | Flag();
- auto flagsSet = Flag() | Flag();
- for (const auto &conversion : conversions) {
- flagsMask |= conversion.flag;
- if (flags & int(conversion.saved)) {
- flagsSet |= conversion.flag;
- }
- }
- user->setFlags((user->flags() & ~flagsMask) | flagsSet);
- }
- user->setAccessHash(access);
- user->updateLastseen((version > 1)
- ? Data::LastseenStatus::FromSerialized(lastseen)
- : Data::LastseenStatus::FromLegacy(lastseen));
- user->setIsContact(contact == 1);
- user->setBotInfoVersion(botInfoVersion);
- if (!inlinePlaceholder.isEmpty() && user->isBot()) {
- user->botInfo->inlinePlaceholder = inlinePlaceholder;
- }
- if (user->id == selfId) {
- user->input = MTP_inputPeerSelf();
- user->inputUser = MTP_inputUserSelf();
- } else {
- user->input = MTP_inputPeerUser(MTP_long(peerToUser(user->id).bare), MTP_long(user->accessHash()));
- user->inputUser = MTP_inputUser(MTP_long(peerToUser(user->id).bare), MTP_long(user->accessHash()));
- }
- }
- } else if (const auto chat = result->asChat()) {
- QString name, inviteLink;
- qint32 count, date, version, field1, field2;
- quint32 flags;
- stream
- >> name
- >> count
- >> date
- >> version
- >> field1
- >> field2
- >> flags
- >> inviteLink;
- if (apply) {
- const auto creator = UserId(
- BareId(uint32(field1)) | (BareId(uint32(field2) >> 8) << 32));
- chat->setName(name);
- chat->count = count;
- chat->date = date;
- // We don't save participants, admin status and banned rights.
- // So we don't restore the version field, info is still unknown.
- chat->setVersion(0);
- if (streamAppVersion >= 2008007) {
- chat->setFlags(ChatDataFlags::from_raw(flags));
- } else {
- const auto oldForbidden = ((uint32(field2) & 0xFF) == 1);
- using Saved = MTPDchat::Flag;
- using Flag = ChatDataFlag;
- struct Conversion {
- Saved saved;
- Flag flag;
- };
- const auto conversions = {
- Conversion{ Saved::f_left, Flag::Left },
- Conversion{ Saved::f_creator, Flag::Creator },
- Conversion{ Saved::f_deactivated, Flag::Deactivated },
- Conversion{ Saved(1U << 31), Flag::Forbidden },
- Conversion{ Saved::f_call_active, Flag::CallActive },
- Conversion{ Saved::f_call_not_empty, Flag::CallNotEmpty },
- };
- auto flagsMask = Flag() | Flag();
- auto flagsSet = Flag() | Flag();
- if (streamAppVersion >= 9012) {
- for (const auto &conversion : conversions) {
- flagsMask |= conversion.flag;
- if (flags & int(conversion.saved)) {
- flagsSet |= conversion.flag;
- }
- }
- } else {
- // flags was haveLeft
- if (flags == 1) {
- flagsSet |= Flag::Left;
- }
- }
- if (oldForbidden) {
- flagsSet |= Flag::Forbidden;
- }
- chat->setFlags((chat->flags() & ~flagsMask) | flagsSet);
- }
- chat->creator = creator;
- chat->setInviteLink(inviteLink);
- chat->input = MTP_inputPeerChat(MTP_long(peerToChat(chat->id).bare));
- }
- } else if (const auto channel = result->asChannel()) {
- QString name, inviteLink;
- quint64 access;
- qint32 date, version, oldForbidden;
- quint32 flags;
- stream
- >> name
- >> access
- >> date
- >> version
- >> oldForbidden
- >> flags
- >> inviteLink;
- userpicAccessHash = access;
- if (apply) {
- channel->setName(name, QString());
- channel->access = access;
- channel->date = date;
- if (streamAppVersion >= 2008007) {
- channel->setFlags(ChannelDataFlags::from_raw(flags));
- } else {
- using Saved = MTPDchannel::Flag;
- using Flag = ChannelDataFlag;
- struct Conversion {
- Saved saved;
- Flag flag;
- };
- const auto conversions = {
- Conversion{ Saved::f_broadcast, Flag::Broadcast },
- Conversion{ Saved::f_verified, Flag::Verified},
- Conversion{ Saved::f_scam, Flag::Scam},
- Conversion{ Saved::f_fake, Flag::Fake},
- Conversion{ Saved::f_megagroup, Flag::Megagroup},
- Conversion{ Saved::f_gigagroup, Flag::Gigagroup},
- Conversion{ Saved::f_username, Flag::Username},
- Conversion{ Saved::f_signatures, Flag::Signatures},
- Conversion{ Saved::f_has_link, Flag::HasLink},
- Conversion{
- Saved::f_slowmode_enabled,
- Flag::SlowmodeEnabled },
- Conversion{ Saved::f_call_active, Flag::CallActive },
- Conversion{ Saved::f_call_not_empty, Flag::CallNotEmpty },
- Conversion{ Saved(1U << 31), Flag::Forbidden },
- Conversion{ Saved::f_left, Flag::Left },
- Conversion{ Saved::f_creator, Flag::Creator },
- };
- auto flagsMask = Flag() | Flag();
- auto flagsSet = Flag() | Flag();
- for (const auto &conversion : conversions) {
- flagsMask |= conversion.flag;
- if (flags & int(conversion.saved)) {
- flagsSet |= conversion.flag;
- }
- }
- if (oldForbidden) {
- flagsSet |= Flag::Forbidden;
- }
- channel->setFlags((channel->flags() & ~flagsMask) | flagsSet);
- }
- channel->setInviteLink(inviteLink);
- channel->input = MTP_inputPeerChannel(MTP_long(peerToChannel(channel->id).bare), MTP_long(access));
- channel->inputChannel = MTP_inputChannel(MTP_long(peerToChannel(channel->id).bare), MTP_long(access));
- }
- }
- if (apply) {
- const auto location = userpic->convertToModernPeerPhoto(
- result->id.value,
- userpicAccessHash,
- photoId);
- result->setUserpic(photoId, location, (photoHasVideo == 1));
- }
- return result;
- }
- QString peekUserPhone(int streamAppVersion, QDataStream &stream) {
- quint64 peerIdSerialized = 0, versionTag = 0, photoId = 0;
- qint32 version = 0, photoHasVideo = 0;
- stream >> peerIdSerialized >> versionTag;
- const auto peerId = DeserializePeerId(peerIdSerialized);
- DEBUG_LOG(("peekUserPhone.id: %1").arg(peerId.value));
- if (!peerId || !peerIsUser(peerId)) {
- return nullptr;
- }
- if (versionTag == kVersionTag) {
- stream >> version >> photoId;
- } else {
- photoId = versionTag;
- }
- if (!readImageLocation(streamAppVersion, stream)) {
- return nullptr;
- }
- if (version > 0) {
- stream >> photoHasVideo;
- }
- QString first, last, phone;
- stream >> first >> last >> phone;
- DEBUG_LOG(("peekUserPhone.data: %1 %2 %3"
- ).arg(first, last, phone));
- return phone;
- }
- } // namespace Serialize
|