2
0
mirror of https://github.com/telegramdesktop/tdesktop synced 2025-08-31 06:26:18 +00:00

Version bumped to 0.9.61 stable.

Merge branch 'archived_stickers' into cancel_reset.

Conflicts:
	Telegram/Resources/winrc/Telegram.rc
	Telegram/Resources/winrc/Updater.rc
	Telegram/SourceFiles/app.cpp
	Telegram/SourceFiles/core/version.h
	Telegram/SourceFiles/localstorage.cpp
	Telegram/Telegram.vcxproj.filters
	Telegram/Telegram.xcodeproj/project.pbxproj
	Telegram/build/version
This commit is contained in:
John Preston
2016-07-25 22:54:40 +03:00
61 changed files with 3998 additions and 1344 deletions

View File

@@ -30,6 +30,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "data/data_abstract_structure.h"
#include "history/history_service_layout.h"
#include "media/media_audio.h"
#include "inline_bots/inline_bot_layout_item.h"
#include "application.h"
#include "fileuploader.h"
#include "mainwidget.h"
@@ -382,397 +383,413 @@ namespace {
return (online > now);
}
UserData *feedUsers(const MTPVector<MTPUser> &users) {
UserData *result = nullptr;
for_const (auto &user, users.c_vector().v) {
UserData *data = nullptr;
bool wasContact = false, minimal = false;
const MTPUserStatus *status = 0, emptyStatus = MTP_userStatusEmpty();
UserData *feedUser(const MTPUser &user) {
UserData *data = nullptr;
bool wasContact = false, minimal = false;
const MTPUserStatus *status = 0, emptyStatus = MTP_userStatusEmpty();
Notify::PeerUpdate update;
using UpdateFlag = Notify::PeerUpdate::Flag;
Notify::PeerUpdate update;
using UpdateFlag = Notify::PeerUpdate::Flag;
switch (user.type()) {
case mtpc_userEmpty: {
const auto &d(user.c_userEmpty());
switch (user.type()) {
case mtpc_userEmpty: {
auto &d(user.c_userEmpty());
PeerId peer(peerFromUser(d.vid.v));
data = App::user(peer);
auto canShareThisContact = data->canShareThisContactFast();
wasContact = data->isContact();
PeerId peer(peerFromUser(d.vid.v));
data = App::user(peer);
auto canShareThisContact = data->canShareThisContactFast();
wasContact = data->isContact();
data->input = MTP_inputPeerUser(d.vid, MTP_long(0));
data->inputUser = MTP_inputUser(d.vid, MTP_long(0));
data->input = MTP_inputPeerUser(d.vid, MTP_long(0));
data->inputUser = MTP_inputUser(d.vid, MTP_long(0));
data->setName(lang(lng_deleted), QString(), QString(), QString());
data->setPhoto(MTP_userProfilePhotoEmpty());
data->access = UserNoAccess;
data->flags = 0;
data->setBotInfoVersion(-1);
status = &emptyStatus;
data->contact = -1;
if (canShareThisContact != data->canShareThisContactFast()) update.flags |= UpdateFlag::UserCanShareContact;
if (wasContact != data->isContact()) update.flags |= UpdateFlag::UserIsContact;
} break;
case mtpc_user: {
auto &d(user.c_user());
minimal = d.is_min();
PeerId peer(peerFromUser(d.vid.v));
data = App::user(peer);
auto canShareThisContact = data->canShareThisContactFast();
wasContact = data->isContact();
if (!minimal) {
data->flags = d.vflags.v;
if (d.is_self()) {
data->input = MTP_inputPeerSelf();
data->inputUser = MTP_inputUserSelf();
} else if (!d.has_access_hash()) {
data->input = MTP_inputPeerUser(d.vid, MTP_long((data->access == UserNoAccess) ? 0 : data->access));
data->inputUser = MTP_inputUser(d.vid, MTP_long((data->access == UserNoAccess) ? 0 : data->access));
} else {
data->input = MTP_inputPeerUser(d.vid, d.vaccess_hash);
data->inputUser = MTP_inputUser(d.vid, d.vaccess_hash);
}
if (d.is_restricted()) {
data->setRestrictionReason(extractRestrictionReason(qs(d.vrestriction_reason)));
} else {
data->setRestrictionReason(QString());
}
}
if (d.is_deleted()) {
if (!data->phone().isEmpty()) {
data->setPhone(QString());
update.flags |= UpdateFlag::UserPhoneChanged;
}
data->setName(lang(lng_deleted), QString(), QString(), QString());
data->setPhoto(MTP_userProfilePhotoEmpty());
data->access = UserNoAccess;
data->flags = 0;
data->setBotInfoVersion(-1);
status = &emptyStatus;
data->contact = -1;
} else {
// apply first_name and last_name from minimal user only if we don't have
// local values for first name and last name already, otherwise skip
bool noLocalName = data->firstName.isEmpty() && data->lastName.isEmpty();
QString fname = (!minimal || noLocalName) ? (d.has_first_name() ? textOneLine(qs(d.vfirst_name)) : QString()) : data->firstName;
QString lname = (!minimal || noLocalName) ? (d.has_last_name() ? textOneLine(qs(d.vlast_name)) : QString()) : data->lastName;
if (canShareThisContact != data->canShareThisContactFast()) update.flags |= UpdateFlag::UserCanShareContact;
if (wasContact != data->isContact()) update.flags |= UpdateFlag::UserIsContact;
} break;
case mtpc_user: {
const auto &d(user.c_user());
minimal = d.is_min();
QString phone = minimal ? data->phone() : (d.has_phone() ? qs(d.vphone) : QString());
QString uname = minimal ? data->username : (d.has_username() ? textOneLine(qs(d.vusername)) : QString());
PeerId peer(peerFromUser(d.vid.v));
data = App::user(peer);
auto canShareThisContact = data->canShareThisContactFast();
wasContact = data->isContact();
if (!minimal) {
data->flags = d.vflags.v;
if (d.is_self()) {
data->input = MTP_inputPeerSelf();
data->inputUser = MTP_inputUserSelf();
} else if (!d.has_access_hash()) {
data->input = MTP_inputPeerUser(d.vid, MTP_long((data->access == UserNoAccess) ? 0 : data->access));
data->inputUser = MTP_inputUser(d.vid, MTP_long((data->access == UserNoAccess) ? 0 : data->access));
} else {
data->input = MTP_inputPeerUser(d.vid, d.vaccess_hash);
data->inputUser = MTP_inputUser(d.vid, d.vaccess_hash);
}
if (d.is_restricted()) {
data->setRestrictionReason(extractRestrictionReason(qs(d.vrestriction_reason)));
} else {
data->setRestrictionReason(QString());
}
bool phoneChanged = (data->phone() != phone);
if (phoneChanged) {
data->setPhone(phone);
update.flags |= UpdateFlag::UserPhoneChanged;
}
if (d.is_deleted()) {
if (!data->phone().isEmpty()) {
data->setPhone(QString());
update.flags |= UpdateFlag::UserPhoneChanged;
}
data->setName(lang(lng_deleted), QString(), QString(), QString());
data->setPhoto(MTP_userProfilePhotoEmpty());
data->access = UserNoAccess;
status = &emptyStatus;
bool nameChanged = (data->firstName != fname) || (data->lastName != lname);
bool showPhone = !isServiceUser(data->id) && !d.is_self() && !d.is_contact() && !d.is_mutual_contact();
bool showPhoneChanged = !isServiceUser(data->id) && !d.is_self() && ((showPhone && data->contact) || (!showPhone && !data->contact));
if (minimal) {
showPhoneChanged = false;
showPhone = !isServiceUser(data->id) && (data->id != peerFromUser(MTP::authedId())) && !data->contact;
}
// see also Local::readPeer
QString pname = (showPhoneChanged || phoneChanged || nameChanged) ? ((showPhone && !phone.isEmpty()) ? formatPhone(phone) : QString()) : data->nameOrPhone;
if (!minimal && d.is_self() && uname != data->username) {
SignalHandlers::setCrashAnnotation("Username", uname);
}
data->setName(fname, lname, pname, uname);
if (d.has_photo()) {
data->setPhoto(d.vphoto);
} else {
// apply first_name and last_name from minimal user only if we don't have
// local values for first name and last name already, otherwise skip
bool noLocalName = data->firstName.isEmpty() && data->lastName.isEmpty();
QString fname = (!minimal || noLocalName) ? (d.has_first_name() ? textOneLine(qs(d.vfirst_name)) : QString()) : data->firstName;
QString lname = (!minimal || noLocalName) ? (d.has_last_name() ? textOneLine(qs(d.vlast_name)) : QString()) : data->lastName;
QString phone = minimal ? data->phone() : (d.has_phone() ? qs(d.vphone) : QString());
QString uname = minimal ? data->username : (d.has_username() ? textOneLine(qs(d.vusername)) : QString());
bool phoneChanged = (data->phone() != phone);
if (phoneChanged) {
data->setPhone(phone);
update.flags |= UpdateFlag::UserPhoneChanged;
}
bool nameChanged = (data->firstName != fname) || (data->lastName != lname);
bool showPhone = !isServiceUser(data->id) && !d.is_self() && !d.is_contact() && !d.is_mutual_contact();
bool showPhoneChanged = !isServiceUser(data->id) && !d.is_self() && ((showPhone && data->contact) || (!showPhone && !data->contact));
if (minimal) {
showPhoneChanged = false;
showPhone = !isServiceUser(data->id) && (data->id != peerFromUser(MTP::authedId())) && !data->contact;
}
// see also Local::readPeer
QString pname = (showPhoneChanged || phoneChanged || nameChanged) ? ((showPhone && !phone.isEmpty()) ? formatPhone(phone) : QString()) : data->nameOrPhone;
if (!minimal && d.is_self() && uname != data->username) {
SignalHandlers::setCrashAnnotation("Username", uname);
}
data->setName(fname, lname, pname, uname);
if (d.has_photo()) {
data->setPhoto(d.vphoto);
} else {
data->setPhoto(MTP_userProfilePhotoEmpty());
}
if (d.has_access_hash()) data->access = d.vaccess_hash.v;
status = d.has_status() ? &d.vstatus : &emptyStatus;
data->setPhoto(MTP_userProfilePhotoEmpty());
}
if (!minimal) {
if (d.has_bot_info_version()) {
data->setBotInfoVersion(d.vbot_info_version.v);
data->botInfo->readsAllHistory = d.is_bot_chat_history();
if (data->botInfo->cantJoinGroups != d.is_bot_nochats()) {
data->botInfo->cantJoinGroups = d.is_bot_nochats();
update.flags |= UpdateFlag::BotCanAddToGroups;
}
data->botInfo->inlinePlaceholder = d.has_bot_inline_placeholder() ? '_' + qs(d.vbot_inline_placeholder) : QString();
} else {
data->setBotInfoVersion(-1);
}
data->contact = (d.is_contact() || d.is_mutual_contact()) ? 1 : (data->phone().isEmpty() ? -1 : 0);
if (data->contact == 1 && cReportSpamStatuses().value(data->id, dbiprsHidden) != dbiprsHidden) {
cRefReportSpamStatuses().insert(data->id, dbiprsHidden);
Local::writeReportSpamStatuses();
}
if (d.is_self() && ::self != data) {
::self = data;
if (App::wnd()) App::wnd()->updateGlobalMenu();
if (d.has_access_hash()) data->access = d.vaccess_hash.v;
status = d.has_status() ? &d.vstatus : &emptyStatus;
}
if (!minimal) {
if (d.has_bot_info_version()) {
data->setBotInfoVersion(d.vbot_info_version.v);
data->botInfo->readsAllHistory = d.is_bot_chat_history();
if (data->botInfo->cantJoinGroups != d.is_bot_nochats()) {
data->botInfo->cantJoinGroups = d.is_bot_nochats();
update.flags |= UpdateFlag::BotCanAddToGroups;
}
data->botInfo->inlinePlaceholder = d.has_bot_inline_placeholder() ? '_' + qs(d.vbot_inline_placeholder) : QString();
} else {
data->setBotInfoVersion(-1);
}
if (canShareThisContact != data->canShareThisContactFast()) update.flags |= UpdateFlag::UserCanShareContact;
if (wasContact != data->isContact()) update.flags |= UpdateFlag::UserIsContact;
} break;
}
if (!data) continue;
if (minimal) {
if (data->loadedStatus == PeerData::NotLoaded) {
data->loadedStatus = PeerData::MinimalLoaded;
data->contact = (d.is_contact() || d.is_mutual_contact()) ? 1 : (data->phone().isEmpty() ? -1 : 0);
if (data->contact == 1 && cReportSpamStatuses().value(data->id, dbiprsHidden) != dbiprsHidden) {
cRefReportSpamStatuses().insert(data->id, dbiprsHidden);
Local::writeReportSpamStatuses();
}
} else if (data->loadedStatus != PeerData::FullLoaded) {
data->loadedStatus = PeerData::FullLoaded;
}
auto oldOnlineTill = data->onlineTill;
if (status && !minimal) switch (status->type()) {
case mtpc_userStatusEmpty: data->onlineTill = 0; break;
case mtpc_userStatusRecently:
if (data->onlineTill > -10) { // don't modify pseudo-online
data->onlineTill = -2;
}
break;
case mtpc_userStatusLastWeek: data->onlineTill = -3; break;
case mtpc_userStatusLastMonth: data->onlineTill = -4; break;
case mtpc_userStatusOffline: data->onlineTill = status->c_userStatusOffline().vwas_online.v; break;
case mtpc_userStatusOnline: data->onlineTill = status->c_userStatusOnline().vexpires.v; break;
}
if (oldOnlineTill != data->onlineTill) {
update.flags |= UpdateFlag::UserOnlineChanged;
}
if (data->contact < 0 && !data->phone().isEmpty() && peerToUser(data->id) != MTP::authedId()) {
data->contact = 0;
}
if (App::main()) {
if ((data->contact > 0 && !wasContact) || (wasContact && data->contact < 1)) {
Notify::userIsContactChanged(data);
}
markPeerUpdated(data);
if (update.flags) {
update.peer = data;
Notify::peerUpdatedDelayed(update);
if (d.is_self() && ::self != data) {
::self = data;
if (App::wnd()) App::wnd()->updateGlobalMenu();
}
}
result = data;
if (canShareThisContact != data->canShareThisContactFast()) update.flags |= UpdateFlag::UserCanShareContact;
if (wasContact != data->isContact()) update.flags |= UpdateFlag::UserIsContact;
} break;
}
if (!data) {
return nullptr;
}
if (minimal) {
if (data->loadedStatus == PeerData::NotLoaded) {
data->loadedStatus = PeerData::MinimalLoaded;
}
} else if (data->loadedStatus != PeerData::FullLoaded) {
data->loadedStatus = PeerData::FullLoaded;
}
auto oldOnlineTill = data->onlineTill;
if (status && !minimal) switch (status->type()) {
case mtpc_userStatusEmpty: data->onlineTill = 0; break;
case mtpc_userStatusRecently:
if (data->onlineTill > -10) { // don't modify pseudo-online
data->onlineTill = -2;
}
break;
case mtpc_userStatusLastWeek: data->onlineTill = -3; break;
case mtpc_userStatusLastMonth: data->onlineTill = -4; break;
case mtpc_userStatusOffline: data->onlineTill = status->c_userStatusOffline().vwas_online.v; break;
case mtpc_userStatusOnline: data->onlineTill = status->c_userStatusOnline().vexpires.v; break;
}
if (oldOnlineTill != data->onlineTill) {
update.flags |= UpdateFlag::UserOnlineChanged;
}
if (data->contact < 0 && !data->phone().isEmpty() && peerToUser(data->id) != MTP::authedId()) {
data->contact = 0;
}
if (App::main()) {
if ((data->contact > 0 && !wasContact) || (wasContact && data->contact < 1)) {
Notify::userIsContactChanged(data);
}
markPeerUpdated(data);
if (update.flags) {
update.peer = data;
Notify::peerUpdatedDelayed(update);
}
}
return data;
}
UserData *feedUsers(const MTPVector<MTPUser> &users) {
UserData *result = nullptr;
for_const (auto &user, users.c_vector().v) {
if (auto feededUser = feedUser(user)) {
result = feededUser;
}
}
return result;
}
PeerData *feedChat(const MTPChat &chat) {
PeerData *data = nullptr;
bool minimal = false;
Notify::PeerUpdate update;
using UpdateFlag = Notify::PeerUpdate::Flag;
switch (chat.type()) {
case mtpc_chat: {
auto &d(chat.c_chat());
data = App::chat(peerFromChat(d.vid.v));
auto cdata = data->asChat();
auto canEdit = cdata->canEdit();
if (cdata->version < d.vversion.v) {
cdata->version = d.vversion.v;
cdata->invalidateParticipants();
}
data->input = MTP_inputPeerChat(d.vid);
cdata->setName(qs(d.vtitle));
cdata->setPhoto(d.vphoto);
cdata->date = d.vdate.v;
if (d.has_migrated_to() && d.vmigrated_to.type() == mtpc_inputChannel) {
const auto &c(d.vmigrated_to.c_inputChannel());
ChannelData *channel = App::channel(peerFromChannel(c.vchannel_id));
if (!channel->mgInfo) {
channel->flags |= MTPDchannel::Flag::f_megagroup;
channel->flagsUpdated();
}
if (!channel->access) {
channel->input = MTP_inputPeerChannel(c.vchannel_id, c.vaccess_hash);
channel->inputChannel = d.vmigrated_to;
channel->access = d.vmigrated_to.c_inputChannel().vaccess_hash.v;
}
bool updatedTo = (cdata->migrateToPtr != channel), updatedFrom = (channel->mgInfo->migrateFromPtr != cdata);
if (updatedTo) {
cdata->migrateToPtr = channel;
}
if (updatedFrom) {
channel->mgInfo->migrateFromPtr = cdata;
if (History *h = App::historyLoaded(cdata->id)) {
if (History *hto = App::historyLoaded(channel->id)) {
if (!h->isEmpty()) {
h->clear(true);
}
if (hto->inChatList(Dialogs::Mode::All) && h->inChatList(Dialogs::Mode::All)) {
App::removeDialog(h);
}
}
}
Notify::migrateUpdated(channel);
update.flags |= UpdateFlag::MigrationChanged;
}
if (updatedTo) {
Notify::migrateUpdated(cdata);
update.flags |= UpdateFlag::MigrationChanged;
}
}
if (!(cdata->flags & MTPDchat::Flag::f_admins_enabled) && (d.vflags.v & MTPDchat::Flag::f_admins_enabled)) {
cdata->invalidateParticipants();
}
cdata->flags = d.vflags.v;
cdata->count = d.vparticipants_count.v;
cdata->isForbidden = false;
if (canEdit != cdata->canEdit()) {
update.flags |= UpdateFlag::ChatCanEdit;
}
} break;
case mtpc_chatForbidden: {
auto &d(chat.c_chatForbidden());
data = App::chat(peerFromChat(d.vid.v));
auto cdata = data->asChat();
auto canEdit = cdata->canEdit();
data->input = MTP_inputPeerChat(d.vid);
cdata->setName(qs(d.vtitle));
cdata->setPhoto(MTP_chatPhotoEmpty());
cdata->date = 0;
cdata->count = -1;
cdata->invalidateParticipants();
cdata->flags = 0;
cdata->isForbidden = true;
if (canEdit != cdata->canEdit()) {
update.flags |= UpdateFlag::ChatCanEdit;
}
} break;
case mtpc_channel: {
auto &d(chat.c_channel());
auto peerId = peerFromChannel(d.vid.v);
minimal = d.is_min();
if (minimal) {
data = App::channelLoaded(peerId);
if (!data) {
return nullptr; // minimal is not loaded, need to make getDifference
}
} else {
data = App::channel(peerId);
data->input = MTP_inputPeerChannel(d.vid, d.has_access_hash() ? d.vaccess_hash : MTP_long(0));
}
auto cdata = data->asChannel();
auto wasInChannel = cdata->amIn();
auto canEditPhoto = cdata->canEditPhoto();
auto canViewAdmins = cdata->canViewAdmins();
auto canViewMembers = cdata->canViewMembers();
auto canAddMembers = cdata->canAddMembers();
auto wasEditor = cdata->amEditor();
if (minimal) {
auto mask = MTPDchannel::Flag::f_broadcast | MTPDchannel::Flag::f_verified | MTPDchannel::Flag::f_megagroup | MTPDchannel::Flag::f_democracy;
cdata->flags = (cdata->flags & ~mask) | (d.vflags.v & mask);
} else {
cdata->inputChannel = MTP_inputChannel(d.vid, d.vaccess_hash);
cdata->access = d.vaccess_hash.v;
cdata->date = d.vdate.v;
if (cdata->version < d.vversion.v) {
cdata->version = d.vversion.v;
}
if (d.is_restricted()) {
cdata->setRestrictionReason(extractRestrictionReason(qs(d.vrestriction_reason)));
} else {
cdata->setRestrictionReason(QString());
}
cdata->flags = d.vflags.v;
}
cdata->flagsUpdated();
QString uname = d.has_username() ? textOneLine(qs(d.vusername)) : QString();
cdata->setName(qs(d.vtitle), uname);
cdata->isForbidden = false;
cdata->setPhoto(d.vphoto);
if (wasInChannel != cdata->amIn()) update.flags |= UpdateFlag::ChannelAmIn;
if (canEditPhoto != cdata->canEditPhoto()) update.flags |= UpdateFlag::ChannelCanEditPhoto;
if (canViewAdmins != cdata->canViewAdmins()) update.flags |= UpdateFlag::ChannelCanViewAdmins;
if (canViewMembers != cdata->canViewMembers()) update.flags |= UpdateFlag::ChannelCanViewMembers;
if (canAddMembers != cdata->canAddMembers()) update.flags |= UpdateFlag::ChannelCanAddMembers;
if (wasEditor != cdata->amEditor()) {
cdata->selfAdminUpdated();
update.flags |= (UpdateFlag::ChannelAmEditor | UpdateFlag::AdminsChanged);
}
} break;
case mtpc_channelForbidden: {
auto &d(chat.c_channelForbidden());
auto peerId = peerFromChannel(d.vid.v);
data = App::channel(peerId);
data->input = MTP_inputPeerChannel(d.vid, d.vaccess_hash);
auto cdata = data->asChannel();
auto wasInChannel = cdata->amIn();
auto canEditPhoto = cdata->canEditPhoto();
auto canViewAdmins = cdata->canViewAdmins();
auto canViewMembers = cdata->canViewMembers();
auto canAddMembers = cdata->canAddMembers();
auto wasEditor = cdata->amEditor();
cdata->inputChannel = MTP_inputChannel(d.vid, d.vaccess_hash);
auto mask = mtpCastFlags(MTPDchannelForbidden::Flag::f_broadcast | MTPDchannelForbidden::Flag::f_megagroup);
cdata->flags = (cdata->flags & ~mask) | (mtpCastFlags(d.vflags) & mask);
cdata->flagsUpdated();
cdata->setName(qs(d.vtitle), QString());
cdata->access = d.vaccess_hash.v;
cdata->setPhoto(MTP_chatPhotoEmpty());
cdata->date = 0;
cdata->setMembersCount(0);
cdata->isForbidden = true;
if (wasInChannel != cdata->amIn()) update.flags |= UpdateFlag::ChannelAmIn;
if (canEditPhoto != cdata->canEditPhoto()) update.flags |= UpdateFlag::ChannelCanEditPhoto;
if (canViewAdmins != cdata->canViewAdmins()) update.flags |= UpdateFlag::ChannelCanViewAdmins;
if (canViewMembers != cdata->canViewMembers()) update.flags |= UpdateFlag::ChannelCanViewMembers;
if (canAddMembers != cdata->canAddMembers()) update.flags |= UpdateFlag::ChannelCanAddMembers;
if (wasEditor != cdata->amEditor()) {
cdata->selfAdminUpdated();
update.flags |= (UpdateFlag::ChannelAmEditor | UpdateFlag::AdminsChanged);
}
} break;
}
if (!data) {
return nullptr;
}
if (minimal) {
if (data->loadedStatus == PeerData::NotLoaded) {
data->loadedStatus = PeerData::MinimalLoaded;
}
} else if (data->loadedStatus != PeerData::FullLoaded) {
data->loadedStatus = PeerData::FullLoaded;
}
if (App::main()) {
markPeerUpdated(data);
if (update.flags) {
update.peer = data;
Notify::peerUpdatedDelayed(update);
}
}
return data;
}
PeerData *feedChats(const MTPVector<MTPChat> &chats) {
PeerData *result = nullptr;
for_const (auto &chat, chats.c_vector().v) {
PeerData *data = nullptr;
bool minimal = false;
Notify::PeerUpdate update;
using UpdateFlag = Notify::PeerUpdate::Flag;
switch (chat.type()) {
case mtpc_chat: {
auto &d(chat.c_chat());
data = App::chat(peerFromChat(d.vid.v));
auto cdata = data->asChat();
auto canEdit = cdata->canEdit();
if (cdata->version < d.vversion.v) {
cdata->version = d.vversion.v;
cdata->invalidateParticipants();
}
data->input = MTP_inputPeerChat(d.vid);
cdata->setName(qs(d.vtitle));
cdata->setPhoto(d.vphoto);
cdata->date = d.vdate.v;
if (d.has_migrated_to() && d.vmigrated_to.type() == mtpc_inputChannel) {
const auto &c(d.vmigrated_to.c_inputChannel());
ChannelData *channel = App::channel(peerFromChannel(c.vchannel_id));
if (!channel->mgInfo) {
channel->flags |= MTPDchannel::Flag::f_megagroup;
channel->flagsUpdated();
}
if (!channel->access) {
channel->input = MTP_inputPeerChannel(c.vchannel_id, c.vaccess_hash);
channel->inputChannel = d.vmigrated_to;
channel->access = d.vmigrated_to.c_inputChannel().vaccess_hash.v;
}
bool updatedTo = (cdata->migrateToPtr != channel), updatedFrom = (channel->mgInfo->migrateFromPtr != cdata);
if (updatedTo) {
cdata->migrateToPtr = channel;
}
if (updatedFrom) {
channel->mgInfo->migrateFromPtr = cdata;
if (History *h = App::historyLoaded(cdata->id)) {
if (History *hto = App::historyLoaded(channel->id)) {
if (!h->isEmpty()) {
h->clear(true);
}
if (hto->inChatList(Dialogs::Mode::All) && h->inChatList(Dialogs::Mode::All)) {
App::removeDialog(h);
}
}
}
Notify::migrateUpdated(channel);
update.flags |= UpdateFlag::MigrationChanged;
}
if (updatedTo) {
Notify::migrateUpdated(cdata);
update.flags |= UpdateFlag::MigrationChanged;
}
}
if (!(cdata->flags & MTPDchat::Flag::f_admins_enabled) && (d.vflags.v & MTPDchat::Flag::f_admins_enabled)) {
cdata->invalidateParticipants();
}
cdata->flags = d.vflags.v;
cdata->count = d.vparticipants_count.v;
cdata->isForbidden = false;
if (canEdit != cdata->canEdit()) {
update.flags |= UpdateFlag::ChatCanEdit;
}
} break;
case mtpc_chatForbidden: {
auto &d(chat.c_chatForbidden());
data = App::chat(peerFromChat(d.vid.v));
auto cdata = data->asChat();
auto canEdit = cdata->canEdit();
data->input = MTP_inputPeerChat(d.vid);
cdata->setName(qs(d.vtitle));
cdata->setPhoto(MTP_chatPhotoEmpty());
cdata->date = 0;
cdata->count = -1;
cdata->invalidateParticipants();
cdata->flags = 0;
cdata->isForbidden = true;
if (canEdit != cdata->canEdit()) {
update.flags |= UpdateFlag::ChatCanEdit;
}
} break;
case mtpc_channel: {
auto &d(chat.c_channel());
auto peerId = peerFromChannel(d.vid.v);
minimal = d.is_min();
if (minimal) {
data = App::channelLoaded(peerId);
if (!data) {
continue; // minimal is not loaded, need to make getDifference
}
} else {
data = App::channel(peerId);
data->input = MTP_inputPeerChannel(d.vid, d.has_access_hash() ? d.vaccess_hash : MTP_long(0));
}
auto cdata = data->asChannel();
auto wasInChannel = cdata->amIn();
auto canEditPhoto = cdata->canEditPhoto();
auto canViewAdmins = cdata->canViewAdmins();
auto canViewMembers = cdata->canViewMembers();
auto canAddMembers = cdata->canAddMembers();
auto wasEditor = cdata->amEditor();
if (minimal) {
auto mask = MTPDchannel::Flag::f_broadcast | MTPDchannel::Flag::f_verified | MTPDchannel::Flag::f_megagroup | MTPDchannel::Flag::f_democracy;
cdata->flags = (cdata->flags & ~mask) | (d.vflags.v & mask);
} else {
cdata->inputChannel = MTP_inputChannel(d.vid, d.vaccess_hash);
cdata->access = d.vaccess_hash.v;
cdata->date = d.vdate.v;
if (cdata->version < d.vversion.v) {
cdata->version = d.vversion.v;
}
if (d.is_restricted()) {
cdata->setRestrictionReason(extractRestrictionReason(qs(d.vrestriction_reason)));
} else {
cdata->setRestrictionReason(QString());
}
cdata->flags = d.vflags.v;
}
cdata->flagsUpdated();
QString uname = d.has_username() ? textOneLine(qs(d.vusername)) : QString();
cdata->setName(qs(d.vtitle), uname);
cdata->isForbidden = false;
cdata->setPhoto(d.vphoto);
if (wasInChannel != cdata->amIn()) update.flags |= UpdateFlag::ChannelAmIn;
if (canEditPhoto != cdata->canEditPhoto()) update.flags |= UpdateFlag::ChannelCanEditPhoto;
if (canViewAdmins != cdata->canViewAdmins()) update.flags |= UpdateFlag::ChannelCanViewAdmins;
if (canViewMembers != cdata->canViewMembers()) update.flags |= UpdateFlag::ChannelCanViewMembers;
if (canAddMembers != cdata->canAddMembers()) update.flags |= UpdateFlag::ChannelCanAddMembers;
if (wasEditor != cdata->amEditor()) {
cdata->selfAdminUpdated();
update.flags |= (UpdateFlag::ChannelAmEditor | UpdateFlag::AdminsChanged);
}
} break;
case mtpc_channelForbidden: {
auto &d(chat.c_channelForbidden());
auto peerId = peerFromChannel(d.vid.v);
data = App::channel(peerId);
data->input = MTP_inputPeerChannel(d.vid, d.vaccess_hash);
auto cdata = data->asChannel();
auto wasInChannel = cdata->amIn();
auto canEditPhoto = cdata->canEditPhoto();
auto canViewAdmins = cdata->canViewAdmins();
auto canViewMembers = cdata->canViewMembers();
auto canAddMembers = cdata->canAddMembers();
auto wasEditor = cdata->amEditor();
cdata->inputChannel = MTP_inputChannel(d.vid, d.vaccess_hash);
auto mask = mtpCastFlags(MTPDchannelForbidden::Flag::f_broadcast | MTPDchannelForbidden::Flag::f_megagroup);
cdata->flags = (cdata->flags & ~mask) | (mtpCastFlags(d.vflags) & mask);
cdata->flagsUpdated();
cdata->setName(qs(d.vtitle), QString());
cdata->access = d.vaccess_hash.v;
cdata->setPhoto(MTP_chatPhotoEmpty());
cdata->date = 0;
cdata->setMembersCount(0);
cdata->isForbidden = true;
if (wasInChannel != cdata->amIn()) update.flags |= UpdateFlag::ChannelAmIn;
if (canEditPhoto != cdata->canEditPhoto()) update.flags |= UpdateFlag::ChannelCanEditPhoto;
if (canViewAdmins != cdata->canViewAdmins()) update.flags |= UpdateFlag::ChannelCanViewAdmins;
if (canViewMembers != cdata->canViewMembers()) update.flags |= UpdateFlag::ChannelCanViewMembers;
if (canAddMembers != cdata->canAddMembers()) update.flags |= UpdateFlag::ChannelCanAddMembers;
if (wasEditor != cdata->amEditor()) {
cdata->selfAdminUpdated();
update.flags |= (UpdateFlag::ChannelAmEditor | UpdateFlag::AdminsChanged);
}
} break;
if (auto feededChat = feedChat(chat)) {
result = feededChat;
}
if (!data) continue;
if (minimal) {
if (data->loadedStatus == PeerData::NotLoaded) {
data->loadedStatus = PeerData::MinimalLoaded;
}
} else if (data->loadedStatus != PeerData::FullLoaded) {
data->loadedStatus = PeerData::FullLoaded;
}
if (App::main()) {
markPeerUpdated(data);
if (update.flags) {
update.peer = data;
Notify::peerUpdatedDelayed(update);
}
}
result = data;
}
return result;
}
@@ -1452,7 +1469,7 @@ namespace {
switch (document.type()) {
case mtpc_document: {
const auto &d(document.c_document());
return App::documentSet(d.vid.v, 0, d.vaccess_hash.v, d.vdate.v, d.vattributes.c_vector().v, qs(d.vmime_type), ImagePtr(thumb, "JPG"), d.vdc_id.v, d.vsize.v, StorageImageLocation());
return App::documentSet(d.vid.v, 0, d.vaccess_hash.v, d.vversion.v, d.vdate.v, d.vattributes.c_vector().v, qs(d.vmime_type), ImagePtr(thumb, "JPG"), d.vdc_id.v, d.vsize.v, StorageImageLocation());
} break;
case mtpc_documentEmpty: return App::document(document.c_documentEmpty().vid.v);
}
@@ -1465,14 +1482,14 @@ namespace {
return feedDocument(document.c_document(), convert);
} break;
case mtpc_documentEmpty: {
return App::documentSet(document.c_documentEmpty().vid.v, convert, 0, 0, QVector<MTPDocumentAttribute>(), QString(), ImagePtr(), 0, 0, StorageImageLocation());
return App::documentSet(document.c_documentEmpty().vid.v, convert, 0, 0, 0, QVector<MTPDocumentAttribute>(), QString(), ImagePtr(), 0, 0, StorageImageLocation());
} break;
}
return App::document(0);
}
DocumentData *feedDocument(const MTPDdocument &document, DocumentData *convert) {
return App::documentSet(document.vid.v, convert, document.vaccess_hash.v, document.vdate.v, document.vattributes.c_vector().v, qs(document.vmime_type), App::image(document.vthumb), document.vdc_id.v, document.vsize.v, App::imageLocation(document.vthumb));
return App::documentSet(document.vid.v, convert, document.vaccess_hash.v, document.vversion.v, document.vdate.v, document.vattributes.c_vector().v, qs(document.vmime_type), App::image(document.vthumb), document.vdc_id.v, document.vsize.v, App::imageLocation(document.vthumb));
}
WebPageData *feedWebPage(const MTPDwebPage &webpage, WebPageData *convert) {
@@ -1629,11 +1646,13 @@ namespace {
return i.value();
}
DocumentData *documentSet(const DocumentId &document, DocumentData *convert, const uint64 &access, int32 date, const QVector<MTPDocumentAttribute> &attributes, const QString &mime, const ImagePtr &thumb, int32 dc, int32 size, const StorageImageLocation &thumbLocation) {
DocumentData *documentSet(const DocumentId &document, DocumentData *convert, const uint64 &access, int32 version, int32 date, const QVector<MTPDocumentAttribute> &attributes, const QString &mime, const ImagePtr &thumb, int32 dc, int32 size, const StorageImageLocation &thumbLocation) {
bool versionChanged = false;
bool sentSticker = false;
if (convert) {
MediaKey oldKey = convert->mediaKey();
if (convert->id != document) {
bool idChanged = (convert->id != document);
if (idChanged) {
DocumentsData::iterator i = ::documentsData.find(convert->id);
if (i != ::documentsData.cend() && i.value() == convert) {
::documentsData.erase(i);
@@ -1645,10 +1664,11 @@ namespace {
}
if (date) {
convert->setattributes(attributes);
versionChanged = convert->setRemoteVersion(version);
convert->setRemoteLocation(dc, access);
convert->date = date;
convert->mime = mime;
if (!thumb->isNull() && (convert->thumb->isNull() || convert->thumb->width() < thumb->width() || convert->thumb->height() < thumb->height())) {
if (!thumb->isNull() && (convert->thumb->isNull() || convert->thumb->width() < thumb->width() || convert->thumb->height() < thumb->height() || versionChanged)) {
updateImage(convert->thumb, thumb);
}
convert->size = size;
@@ -1658,7 +1678,7 @@ namespace {
}
MediaKey newKey = convert->mediaKey();
if (newKey != oldKey) {
if (idChanged) {
if (convert->voice()) {
Local::copyAudio(oldKey, newKey);
} else if (convert->sticker() || convert->isAnimation()) {
@@ -1677,7 +1697,7 @@ namespace {
if (convert) {
result = convert;
} else {
result = DocumentData::create(document, dc, access, attributes);
result = DocumentData::create(document, dc, access, version, attributes);
result->date = date;
result->mime = mime;
result->thumb = thumb;
@@ -1692,12 +1712,13 @@ namespace {
result = i.value();
if (result != convert && date) {
result->setattributes(attributes);
versionChanged = result->setRemoteVersion(version);
if (!result->isValid()) {
result->setRemoteLocation(dc, access);
}
result->date = date;
result->mime = mime;
if (!thumb->isNull() && (result->thumb->isNull() || result->thumb->width() < thumb->width() || result->thumb->height() < thumb->height())) {
if (!thumb->isNull() && (result->thumb->isNull() || result->thumb->width() < thumb->width() || result->thumb->height() < thumb->height() || versionChanged)) {
result->thumb = thumb;
}
result->size = size;
@@ -1710,6 +1731,30 @@ namespace {
if (sentSticker && App::main()) {
App::main()->incrementSticker(result);
}
if (versionChanged) {
if (result->sticker() && result->sticker()->set.type() == mtpc_inputStickerSetID) {
auto it = Global::StickerSets().constFind(result->sticker()->set.c_inputStickerSetID().vid.v);
if (it != Global::StickerSets().cend()) {
if (it->id == Stickers::CloudRecentSetId) {
Local::writeRecentStickers();
} else if (it->flags & MTPDstickerSet::Flag::f_archived) {
Local::writeArchivedStickers();
} else if (it->flags & MTPDstickerSet::Flag::f_installed) {
Local::writeInstalledStickers();
}
if (it->flags & MTPDstickerSet_ClientFlag::f_featured) {
Local::writeFeaturedStickers();
}
}
}
auto &items = App::documentItems();
auto i = items.constFind(result);
if (i != items.cend()) {
for (auto j = i->cbegin(), e = i->cend(); j != e; ++j) {
j.key()->setPendingInitDimensions();
}
}
}
return result;
}
@@ -1977,6 +2022,11 @@ namespace {
Global::SetStickerSets(Stickers::Sets());
Global::SetStickerSetsOrder(Stickers::Order());
Global::SetLastStickersUpdate(0);
Global::SetLastRecentStickersUpdate(0);
Global::SetFeaturedStickerSetsOrder(Stickers::Order());
Global::SetFeaturedStickerSetsUnreadCount(0);
Global::SetLastFeaturedStickersUpdate(0);
Global::SetArchivedStickerSetsOrder(Stickers::Order());
cSetSavedGifs(SavedGifs());
cSetLastSavedGifsUpdate(0);
cSetReportSpamStatuses(ReportSpamStatuses());