tdesktop/Telegram/SourceFiles/storage/serialize_common.cpp

295 lines
8.6 KiB
C++

/*
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_common.h"
#include "auth_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"
namespace Serialize {
void writeStorageImageLocation(
QDataStream &stream,
const StorageImageLocation &location) {
stream
<< qint32(location.width())
<< qint32(location.height())
<< qint32(location.dc())
<< quint64(location.volume())
<< qint32(location.local())
<< quint64(location.secret());
stream << location.fileReference();
}
StorageImageLocation readStorageImageLocation(
int streamAppVersion,
QDataStream &stream) {
qint32 width, height, dc, local;
quint64 volume, secret;
QByteArray fileReference;
stream >> width >> height >> dc >> volume >> local >> secret;
if (streamAppVersion >= 1003013) {
stream >> fileReference;
}
return StorageImageLocation(
width,
height,
dc,
volume,
local,
secret,
fileReference);
}
int storageImageLocationSize(const StorageImageLocation &location) {
// width + height + dc + volume + local + secret + fileReference
return sizeof(qint32)
+ sizeof(qint32)
+ sizeof(qint32)
+ sizeof(quint64)
+ sizeof(qint32)
+ sizeof(quint64)
+ bytearraySize(location.fileReference());
}
uint32 peerSize(not_null<PeerData*> peer) {
uint32 result = sizeof(quint64)
+ sizeof(quint64)
+ storageImageLocationSize(peer->userpicLocation());
if (peer->isUser()) {
UserData *user = peer->asUser();
// first + last + phone + username + access
result += stringSize(user->firstName) + stringSize(user->lastName) + stringSize(user->phone()) + stringSize(user->username) + sizeof(quint64);
// flags
if (AppVersion >= 9012) {
result += sizeof(qint32);
}
// onlineTill + contact + botInfoVersion
result += sizeof(qint32) + sizeof(qint32) + sizeof(qint32);
} else if (peer->isChat()) {
ChatData *chat = peer->asChat();
// name + count + date + version + admin + old forbidden + left + inviteLink
result += stringSize(chat->name) + sizeof(qint32) + sizeof(qint32) + sizeof(qint32) + sizeof(qint32) + sizeof(qint32) + sizeof(quint32) + stringSize(chat->inviteLink());
} else if (peer->isChannel()) {
ChannelData *channel = peer->asChannel();
// name + access + date + version + old forbidden + flags + inviteLink
result += stringSize(channel->name) + sizeof(quint64) + sizeof(qint32) + sizeof(qint32) + sizeof(qint32) + sizeof(quint32) + stringSize(channel->inviteLink());
}
return result;
}
void writePeer(QDataStream &stream, PeerData *peer) {
stream << quint64(peer->id) << quint64(peer->userpicPhotoId());
writeStorageImageLocation(stream, peer->userpicLocation());
if (const auto user = peer->asUser()) {
stream
<< user->firstName
<< user->lastName
<< user->phone()
<< user->username
<< quint64(user->accessHash());
if (AppVersion >= 9012) {
stream << qint32(user->flags());
}
if (AppVersion >= 9016) {
const auto botInlinePlaceholder = user->botInfo
? user->botInfo->inlinePlaceholder
: QString();
stream << botInlinePlaceholder;
}
const auto contactSerialized = [&] {
switch (user->contactStatus()) {
case UserData::ContactStatus::Contact: return 1;
case UserData::ContactStatus::CanAdd: return 0;
case UserData::ContactStatus::PhoneUnknown: return -1;
}
Unexpected("contactStatus in _writePeer()");
}();
stream
<< qint32(user->onlineTill)
<< qint32(contactSerialized)
<< qint32(user->botInfo ? user->botInfo->version : -1);
} else if (const auto chat = peer->asChat()) {
stream
<< chat->name
<< qint32(chat->count)
<< qint32(chat->date)
<< qint32(chat->version())
<< qint32(chat->creator)
<< qint32(0)
<< quint32(chat->flags())
<< chat->inviteLink();
} else if (const auto channel = peer->asChannel()) {
stream
<< channel->name
<< quint64(channel->access)
<< qint32(channel->date)
<< qint32(channel->version())
<< qint32(0)
<< quint32(channel->flags())
<< channel->inviteLink();
}
}
PeerData *readPeer(int streamAppVersion, QDataStream &stream) {
quint64 peerId = 0, photoId = 0;
stream >> peerId >> photoId;
if (!peerId) {
return nullptr;
}
auto photoLoc = readStorageImageLocation(
streamAppVersion,
stream);
PeerData *result = Auth().data().peerLoaded(peerId);
bool wasLoaded = (result != nullptr);
if (!wasLoaded) {
result = Auth().data().peer(peerId);
result->loadedStatus = PeerData::FullLoaded;
}
if (const auto user = result->asUser()) {
QString first, last, phone, username, inlinePlaceholder;
quint64 access;
qint32 flags = 0, onlineTill, contact, botInfoVersion;
stream >> first >> last >> phone >> username >> access;
if (streamAppVersion >= 9012) {
stream >> flags;
}
if (streamAppVersion >= 9016) {
stream >> inlinePlaceholder;
}
stream >> onlineTill >> contact >> botInfoVersion;
const auto showPhone = !user->isServiceUser()
&& (user->id != Auth().userPeerId())
&& (contact <= 0);
const auto pname = (showPhone && !phone.isEmpty())
? App::formatPhone(phone)
: QString();
if (!wasLoaded) {
user->setPhone(phone);
user->setName(first, last, pname, username);
user->setFlags(MTPDuser::Flags::from_raw(flags));
user->setAccessHash(access);
user->onlineTill = onlineTill;
user->setContactStatus((contact > 0)
? UserData::ContactStatus::Contact
: (contact == 0)
? UserData::ContactStatus::CanAdd
: UserData::ContactStatus::PhoneUnknown);
user->setBotInfoVersion(botInfoVersion);
if (!inlinePlaceholder.isEmpty() && user->botInfo) {
user->botInfo->inlinePlaceholder = inlinePlaceholder;
}
if (user->id == Auth().userPeerId()) {
user->input = MTP_inputPeerSelf();
user->inputUser = MTP_inputUserSelf();
} else {
user->input = MTP_inputPeerUser(MTP_int(peerToUser(user->id)), MTP_long(user->accessHash()));
user->inputUser = MTP_inputUser(MTP_int(peerToUser(user->id)), MTP_long(user->accessHash()));
}
}
} else if (const auto chat = result->asChat()) {
QString name, inviteLink;
qint32 count, date, version, creator, oldForbidden;
quint32 flagsData, flags;
stream >> name >> count >> date >> version >> creator >> oldForbidden >> flagsData >> inviteLink;
if (streamAppVersion >= 9012) {
flags = flagsData;
} else {
// flagsData was haveLeft
flags = (flagsData == 1)
? MTPDchat::Flags(MTPDchat::Flag::f_left)
: MTPDchat::Flags(0);
}
if (oldForbidden) {
flags |= quint32(MTPDchat_ClientFlag::f_forbidden);
}
if (!wasLoaded) {
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);
chat->creator = creator;
chat->setFlags(MTPDchat::Flags::from_raw(flags));
chat->setInviteLink(inviteLink);
chat->input = MTP_inputPeerChat(MTP_int(peerToChat(chat->id)));
chat->inputChat = MTP_int(peerToChat(chat->id));
}
} 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;
if (oldForbidden) {
flags |= quint32(MTPDchannel_ClientFlag::f_forbidden);
}
if (!wasLoaded) {
channel->setName(name, QString());
channel->access = access;
channel->date = date;
// We don't save participants, admin status and banned rights.
// So we don't restore the version field, info is still unknown.
channel->setVersion(0);
channel->setFlags(MTPDchannel::Flags::from_raw(flags));
channel->setInviteLink(inviteLink);
channel->input = MTP_inputPeerChannel(MTP_int(peerToChannel(channel->id)), MTP_long(access));
channel->inputChannel = MTP_inputChannel(MTP_int(peerToChannel(channel->id)), MTP_long(access));
}
}
if (!wasLoaded) {
result->setUserpic(
photoId,
photoLoc,
photoLoc.isNull() ? ImagePtr() : Images::Create(photoLoc));
}
return result;
}
QString peekUserPhone(int streamAppVersion, QDataStream &stream) {
quint64 peerId = 0, photoId = 0;
stream >> peerId >> photoId;
DEBUG_LOG(("peekUserPhone.id: %1").arg(peerId));
if (!peerId || !peerIsUser(peerId)) {
return QString();
}
const auto photoLoc = readStorageImageLocation(
streamAppVersion,
stream);
QString first, last, phone;
stream >> first >> last >> phone;
DEBUG_LOG(("peekUserPhone.data: %1 %2 %3"
).arg(first).arg(last).arg(phone));
return phone;
}
} // namespace Serialize