Move MTP::Instance to Main::Account.

This commit is contained in:
John Preston 2019-07-24 10:46:23 +02:00
parent db2018c765
commit 9cf4cf6dca
32 changed files with 715 additions and 526 deletions

View File

@ -534,7 +534,7 @@ bool AuthSession::validateSelf(const MTPUser &user) {
return false;
} else if (user.c_user().vid().v != userId()) {
LOG(("Auth Error: wrong self user received."));
crl::on_main(this, [] { Core::App().logOut(); });
crl::on_main(this, [=] { _account->logOut(); });
return false;
}
return true;
@ -558,6 +558,10 @@ void AuthSession::saveSettingsDelayed(crl::time delay) {
_saveDataTimer.callOnce(delay);
}
not_null<MTP::Instance*> AuthSession::mtp() {
return _account->mtp();
}
void AuthSession::localPasscodeChanged() {
_shouldLockAt = 0;
_autoLockTimer.cancel();

View File

@ -333,6 +333,7 @@ public:
void moveSettingsFrom(AuthSessionSettings &&other);
void saveSettingsDelayed(crl::time delay = kDefaultSaveDelay);
not_null<MTP::Instance*> mtp();
ApiWrap &api() {
return *_api;
}

View File

@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "storage/localstorage.h"
#include "base/qthelp_url.h"
#include "core/application.h"
#include "main/main_account.h"
#include "ui/widgets/checkbox.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/input_fields.h"
@ -1045,7 +1046,7 @@ void ProxiesBoxController::refreshChecker(Item &item) {
const auto type = (item.data.type == Type::Http)
? Variants::Http
: Variants::Tcp;
const auto mtproto = Core::App().mtp();
const auto mtproto = Core::App().activeAccount().mtp();
const auto dcId = mtproto->mainDcId();
item.state = ItemState::Checking;

View File

@ -1155,13 +1155,13 @@ not_null<Ui::MultiSelect*> LanguageBox::createMultiSelect() {
base::binary_guard LanguageBox::Show() {
auto result = base::binary_guard();
const auto manager = Core::App().langCloudManager();
if (manager->languageList().empty()) {
auto &manager = Lang::CurrentCloudManager();
if (manager.languageList().empty()) {
auto guard = std::make_shared<base::binary_guard>(
result.make_guard());
auto alive = std::make_shared<std::unique_ptr<base::Subscription>>(
std::make_unique<base::Subscription>());
**alive = manager->languageListChanged().add_subscription([=] {
**alive = manager.languageListChanged().add_subscription([=] {
const auto show = guard->alive();
*alive = nullptr;
if (show) {
@ -1171,7 +1171,7 @@ base::binary_guard LanguageBox::Show() {
} else {
Ui::show(Box<LanguageBox>());
}
manager->requestLanguageList();
manager.requestLanguageList();
return result;
}

View File

@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/zlib_help.h"
#include "layout.h"
#include "core/application.h"
#include "main/main_account.h"
#include "mainwidget.h"
#include "styles/style_boxes.h"
#include "styles/style_chat_helpers.h"
@ -245,7 +246,7 @@ Loader::Loader(QObject *parent, int id)
, _id(id)
, _size(GetDownloadSize(_id))
, _state(Loading{ 0, _size })
, _mtproto(Core::App().mtp()) {
, _mtproto(Core::App().activeAccount().mtp()) {
const auto ready = [=](std::unique_ptr<MTP::DedicatedLoader> loader) {
if (loader) {
setImplementation(std::move(loader));

View File

@ -72,12 +72,6 @@ constexpr auto kQuitPreventTimeoutMs = 1500;
Application *Application::Instance = nullptr;
struct Application::Private {
UserId authSessionUserId = 0;
QByteArray authSessionUserSerialized;
int32 authSessionUserStreamVersion = 0;
std::unique_ptr<AuthSessionSettings> storedAuthSession;
MTP::Instance::Config mtpConfig;
MTP::AuthKeysList mtpKeysToDestroy;
base::Timer quitTimer;
};
@ -87,6 +81,7 @@ Application::Application(not_null<Launcher*> launcher)
, _private(std::make_unique<Private>())
, _databases(std::make_unique<Storage::Databases>())
, _animationsManager(std::make_unique<Ui::Animations::Manager>())
, _dcOptions(std::make_unique<MTP::DcOptions>())
, _account(std::make_unique<Main::Account>(cDataFile()))
, _langpack(std::make_unique<Lang::Instance>())
, _emojiKeywords(std::make_unique<ChatHelpers::EmojiKeywords>())
@ -95,9 +90,26 @@ Application::Application(not_null<Launcher*> launcher)
, _logoNoMargin(Window::LoadLogoNoMargin()) {
Expects(!_logo.isNull());
Expects(!_logoNoMargin.isNull());
Expects(Instance == nullptr);
Instance = this;
activeAccount().sessionChanges(
) | rpl::start_with_next([=] {
if (_mediaView) {
hideMediaView();
_mediaView->clearData();
}
}, _lifetime);
activeAccount().mtpChanges(
) | rpl::filter([=](MTP::Instance *instance) {
return instance != nullptr;
}) | rpl::start_with_next([=](not_null<MTP::Instance*> mtp) {
_langCloudManager = std::make_unique<Lang::CloudManager>(
langpack(),
mtp);
if (!UpdaterDisabled()) {
UpdateChecker().setMtproto(mtp.get());
}
}, _lifetime);
}
Application::~Application() {
@ -109,14 +121,14 @@ Application::~Application() {
Local::finish();
// Some MTP requests can be cancelled from data clearing.
authSessionDestroy();
unlockTerms();
activeAccount().destroySession();
// The langpack manager should be destroyed before MTProto instance,
// because it is MTP::Sender and it may have pending requests.
_langCloudManager.reset();
_mtproto.reset();
_mtprotoForKeysDestroy.reset();
activeAccount().clearMtp();
Shortcuts::Finish();
@ -199,7 +211,7 @@ void Application::run() {
DEBUG_LOG(("Application Info: passcode needed..."));
} else {
DEBUG_LOG(("Application Info: local map read..."));
startMtp();
activeAccount().startMtp();
DEBUG_LOG(("Application Info: MTP started..."));
if (activeAccount().sessionExists()) {
_window->setupMain();
@ -327,31 +339,24 @@ bool Application::eventFilter(QObject *object, QEvent *e) {
void Application::setCurrentProxy(
const ProxyData &proxy,
ProxyData::Settings settings) {
const auto key = [&](const ProxyData &proxy) {
if (proxy.type == ProxyData::Type::Mtproto) {
return std::make_pair(proxy.host, proxy.port);
}
return std::make_pair(QString(), uint32(0));
};
const auto previousKey = key(
(Global::ProxySettings() == ProxyData::Settings::Enabled
const auto current = [&] {
return (Global::ProxySettings() == ProxyData::Settings::Enabled)
? Global::SelectedProxy()
: ProxyData()));
: ProxyData();
};
const auto was = current();
Global::SetSelectedProxy(proxy);
Global::SetProxySettings(settings);
const auto now = current();
refreshGlobalProxy();
if (_mtproto) {
_mtproto->restart();
if (previousKey != key(proxy)) {
_mtproto->reInitConnection(_mtproto->mainDcId());
}
}
if (_mtprotoForKeysDestroy) {
_mtprotoForKeysDestroy->restart();
}
_proxyChanges.fire({ was, now });
Global::RefConnectionTypeChanged().notify();
}
auto Application::proxyChanges() const -> rpl::producer<ProxyChange> {
return _proxyChanges.events();
}
void Application::badMtprotoConfigurationError() {
if (Global::ProxySettings() == ProxyData::Settings::Enabled
&& !_badProxyDisableBox) {
@ -366,311 +371,16 @@ void Application::badMtprotoConfigurationError() {
}
}
void Application::setMtpMainDcId(MTP::DcId mainDcId) {
Expects(!_mtproto);
_private->mtpConfig.mainDcId = mainDcId;
}
void Application::setMtpKey(MTP::DcId dcId, const MTP::AuthKey::Data &keyData) {
Expects(!_mtproto);
_private->mtpConfig.keys.push_back(std::make_shared<MTP::AuthKey>(MTP::AuthKey::Type::ReadFromFile, dcId, keyData));
}
QByteArray Application::serializeMtpAuthorization() const {
auto serialize = [this](auto mainDcId, auto &keys, auto &keysToDestroy) {
auto keysSize = [](auto &list) {
return sizeof(qint32) + list.size() * (sizeof(qint32) + MTP::AuthKey::Data().size());
};
auto writeKeys = [](QDataStream &stream, auto &keys) {
stream << qint32(keys.size());
for (auto &key : keys) {
stream << qint32(key->dcId());
key->write(stream);
}
};
auto result = QByteArray();
auto size = sizeof(qint32) + sizeof(qint32); // userId + mainDcId
size += keysSize(keys) + keysSize(keysToDestroy);
result.reserve(size);
{
QDataStream stream(&result, QIODevice::WriteOnly);
stream.setVersion(QDataStream::Qt_5_1);
auto currentUserId = activeAccount().sessionExists()
? activeAccount().session().userId()
: 0;
stream << qint32(currentUserId) << qint32(mainDcId);
writeKeys(stream, keys);
writeKeys(stream, keysToDestroy);
DEBUG_LOG(("MTP Info: Keys written, userId: %1, dcId: %2").arg(currentUserId).arg(mainDcId));
}
return result;
};
if (_mtproto) {
auto keys = _mtproto->getKeysForWrite();
auto keysToDestroy = _mtprotoForKeysDestroy ? _mtprotoForKeysDestroy->getKeysForWrite() : MTP::AuthKeysList();
return serialize(_mtproto->mainDcId(), keys, keysToDestroy);
}
auto &keys = _private->mtpConfig.keys;
auto &keysToDestroy = _private->mtpKeysToDestroy;
return serialize(_private->mtpConfig.mainDcId, keys, keysToDestroy);
}
void Application::setAuthSessionUserId(UserId userId) {
Expects(!activeAccount().sessionExists());
_private->authSessionUserId = userId;
}
void Application::setAuthSessionFromStorage(
std::unique_ptr<AuthSessionSettings> data,
QByteArray &&selfSerialized,
int32 selfStreamVersion) {
Expects(!activeAccount().sessionExists());
DEBUG_LOG(("authSessionUserSerialized set: %1"
).arg(selfSerialized.size()));
_private->storedAuthSession = std::move(data);
_private->authSessionUserSerialized = std::move(selfSerialized);
_private->authSessionUserStreamVersion = selfStreamVersion;
}
AuthSessionSettings *Application::getAuthSessionSettings() {
if (_private->authSessionUserId) {
return _private->storedAuthSession
? _private->storedAuthSession.get()
: nullptr;
} else if (activeAccount().sessionExists()) {
return &activeAccount().session().settings();
}
return nullptr;
}
void Application::setMtpAuthorization(const QByteArray &serialized) {
Expects(!_mtproto);
QDataStream stream(serialized);
stream.setVersion(QDataStream::Qt_5_1);
auto userId = Serialize::read<qint32>(stream);
auto mainDcId = Serialize::read<qint32>(stream);
if (stream.status() != QDataStream::Ok) {
LOG(("MTP Error: could not read main fields from serialized mtp authorization."));
return;
}
setAuthSessionUserId(userId);
_private->mtpConfig.mainDcId = mainDcId;
auto readKeys = [&stream](auto &keys) {
auto count = Serialize::read<qint32>(stream);
if (stream.status() != QDataStream::Ok) {
LOG(("MTP Error: could not read keys count from serialized mtp authorization."));
return;
}
keys.reserve(count);
for (auto i = 0; i != count; ++i) {
auto dcId = Serialize::read<qint32>(stream);
auto keyData = Serialize::read<MTP::AuthKey::Data>(stream);
if (stream.status() != QDataStream::Ok) {
LOG(("MTP Error: could not read key from serialized mtp authorization."));
return;
}
keys.push_back(std::make_shared<MTP::AuthKey>(MTP::AuthKey::Type::ReadFromFile, dcId, keyData));
}
};
readKeys(_private->mtpConfig.keys);
readKeys(_private->mtpKeysToDestroy);
LOG(("MTP Info: read keys, current: %1, to destroy: %2").arg(_private->mtpConfig.keys.size()).arg(_private->mtpKeysToDestroy.size()));
}
void Application::startMtp() {
Expects(!_mtproto);
auto config = base::take(_private->mtpConfig);
config.deviceModel = _launcher->deviceModel();
config.systemVersion = _launcher->systemVersion();
_mtproto = std::make_unique<MTP::Instance>(
_dcOptions.get(),
MTP::Instance::Mode::Normal,
std::move(config));
_mtproto->setUserPhone(cLoggedPhoneNumber());
_private->mtpConfig.mainDcId = _mtproto->mainDcId();
_mtproto->setStateChangedHandler([](MTP::ShiftedDcId dc, int32 state) {
if (dc == MTP::maindc()) {
Global::RefConnectionTypeChanged().notify();
}
});
_mtproto->setSessionResetHandler([](MTP::ShiftedDcId shiftedDcId) {
if (App::main() && shiftedDcId == MTP::maindc()) {
App::main()->getDifference();
}
});
if (!_private->mtpKeysToDestroy.empty()) {
destroyMtpKeys(base::take(_private->mtpKeysToDestroy));
}
if (_private->authSessionUserId) {
DEBUG_LOG(("authSessionUserSerialized.size: %1"
).arg(_private->authSessionUserSerialized.size()));
QDataStream peekStream(_private->authSessionUserSerialized);
const auto phone = Serialize::peekUserPhone(
_private->authSessionUserStreamVersion,
peekStream);
const auto flags = MTPDuser::Flag::f_self | (phone.isEmpty()
? MTPDuser::Flag()
: MTPDuser::Flag::f_phone);
authSessionCreate(MTP_user(
MTP_flags(flags),
MTP_int(base::take(_private->authSessionUserId)),
MTPlong(), // access_hash
MTPstring(), // first_name
MTPstring(), // last_name
MTPstring(), // username
MTP_string(phone),
MTPUserProfilePhoto(),
MTPUserStatus(),
MTPint(), // bot_info_version
MTPstring(), // restriction_reason
MTPstring(), // bot_inline_placeholder
MTPstring())); // lang_code
Local::readSelf(
base::take(_private->authSessionUserSerialized),
base::take(_private->authSessionUserStreamVersion));
}
if (_private->storedAuthSession) {
if (activeAccount().sessionExists()) {
activeAccount().session().moveSettingsFrom(
std::move(*_private->storedAuthSession));
}
_private->storedAuthSession.reset();
}
_langCloudManager = std::make_unique<Lang::CloudManager>(
langpack(),
mtp());
if (!UpdaterDisabled()) {
UpdateChecker().setMtproto(mtp());
}
if (activeAccount().sessionExists()) {
// Skip all pending self updates so that we won't Local::writeSelf.
Notify::peerUpdatedSendDelayed();
}
}
void Application::destroyMtpKeys(MTP::AuthKeysList &&keys) {
if (keys.empty()) {
return;
}
if (_mtprotoForKeysDestroy) {
_mtprotoForKeysDestroy->addKeysForDestroy(std::move(keys));
Local::writeMtpData();
return;
}
auto destroyConfig = MTP::Instance::Config();
destroyConfig.mainDcId = MTP::Instance::Config::kNoneMainDc;
destroyConfig.keys = std::move(keys);
destroyConfig.deviceModel = _launcher->deviceModel();
destroyConfig.systemVersion = _launcher->systemVersion();
_mtprotoForKeysDestroy = std::make_unique<MTP::Instance>(
_dcOptions.get(),
MTP::Instance::Mode::KeysDestroyer,
std::move(destroyConfig));
connect(
_mtprotoForKeysDestroy.get(),
&MTP::Instance::allKeysDestroyed,
[=] { allKeysDestroyed(); });
}
void Application::allKeysDestroyed() {
LOG(("MTP Info: all keys scheduled for destroy are destroyed."));
crl::on_main(this, [=] {
_mtprotoForKeysDestroy = nullptr;
Local::writeMtpData();
});
}
void Application::suggestMainDcId(MTP::DcId mainDcId) {
Expects(_mtproto != nullptr);
_mtproto->suggestMainDcId(mainDcId);
if (_private->mtpConfig.mainDcId != MTP::Instance::Config::kNotSetMainDc) {
_private->mtpConfig.mainDcId = mainDcId;
}
}
void Application::destroyStaleAuthorizationKeys() {
Expects(_mtproto != nullptr);
for (const auto &key : _mtproto->getKeysForWrite()) {
// Disable this for now.
if (key->type() == MTP::AuthKey::Type::ReadFromFile) {
_private->mtpKeysToDestroy = _mtproto->getKeysForWrite();
LOG(("MTP Info: destroying stale keys, count: %1"
).arg(_private->mtpKeysToDestroy.size()));
resetAuthorizationKeys();
return;
}
}
}
void Application::configUpdated() {
_configUpdates.fire({});
}
rpl::producer<> Application::configUpdates() const {
return _configUpdates.events();
}
void Application::resetAuthorizationKeys() {
_mtproto = nullptr;
startMtp();
Local::writeMtpData();
}
void Application::startLocalStorage() {
_dcOptions = std::make_unique<MTP::DcOptions>();
_dcOptions->constructFromBuiltIn();
Local::start();
subscribe(_dcOptions->changed(), [this](const MTP::DcOptions::Ids &ids) {
Local::writeSettings();
if (auto instance = mtp()) {
for (auto id : ids) {
if (const auto instance = activeAccount().mtp()) {
for (const auto id : ids) {
instance->restart(id);
}
}
});
activeAccount().sessionChanges(
) | rpl::start_with_next([=] {
crl::on_main(this, [=] {
const auto phone = activeAccount().sessionExists()
? activeAccount().session().user()->phone()
: QString();
const auto support = activeAccount().sessionExists()
&& activeAccount().session().supportMode();
if (cLoggedPhoneNumber() != phone) {
cSetLoggedPhoneNumber(phone);
if (_mtproto) {
_mtproto->setUserPhone(phone);
}
Local::writeSettings();
}
if (_mtproto) {
_mtproto->requestConfig();
}
Platform::SetApplicationIcon(
Window::CreateIcon(&activeAccount()));
Shortcuts::ToggleSupportShortcuts(support);
});
}, _lifetime);
}
void Application::forceLogOut(const TextWithEntities &explanation) {
@ -681,10 +391,7 @@ void Application::forceLogOut(const TextWithEntities &explanation) {
box->setCloseByOutsideClick(false);
connect(box, &QObject::destroyed, [=] {
crl::on_main(this, [=] {
if (AuthSession::Exists()) {
resetAuthorizationKeys();
loggedOut();
}
activeAccount().forcedLogOut();
});
});
}
@ -773,41 +480,6 @@ void Application::writeInstallBetaVersionsSetting() {
_launcher->writeInstallBetaVersionsSetting();
}
void Application::authSessionCreate(const MTPUser &user) {
Expects(_mtproto != nullptr);
_mtproto->setUpdatesHandler(::rpcDone([](
const mtpPrime *from,
const mtpPrime *end) {
if (const auto main = App::main()) {
return main->updateReceived(from, end);
}
return true;
}));
_mtproto->setGlobalFailHandler(::rpcFail([=](const RPCError &error) {
if (activeAccount().sessionExists()) {
crl::on_main(&activeAccount().session(), [=] { logOut(); });
}
return true;
}));
activeAccount().createSession(user);
}
void Application::authSessionDestroy() {
_private->storedAuthSession.reset();
_private->authSessionUserId = 0;
_private->authSessionUserSerialized = {};
if (activeAccount().sessionExists()) {
unlockTerms();
_mtproto->clearGlobalHandlers();
activeAccount().destroySession();
Notify::unreadCounterUpdated();
}
}
int Application::unreadBadge() const {
return activeAccount().sessionExists()
? activeAccount().session().data().unreadBadge()
@ -897,7 +569,9 @@ void Application::lockByPasscode() {
void Application::unlockPasscode() {
clearPasscodeLock();
_window->clearPasscodeLock();
if (_window) {
_window->clearPasscodeLock();
}
}
void Application::clearPasscodeLock() {
@ -1011,48 +685,6 @@ void Application::checkMediaViewActivation() {
}
}
void Application::logOut() {
if (_mtproto) {
_mtproto->logout(::rpcDone([=] {
loggedOut();
}), ::rpcFail([=] {
loggedOut();
return true;
}));
} else {
// We log out because we've forgotten passcode.
// So we just start mtproto from scratch.
startMtp();
loggedOut();
}
}
void Application::loggedOut() {
if (Global::LocalPasscode()) {
Global::SetLocalPasscode(false);
Global::RefLocalPasscodeChanged().notify();
}
clearPasscodeLock();
Media::Player::mixer()->stopAndClear();
Global::SetVoiceMsgPlaybackDoubled(false);
if (const auto window = activeWindow()) {
window->tempDirDelete(Local::ClearManagerAll);
window->setupIntro();
}
if (activeAccount().sessionExists()) {
activeAccount().session().data().clearLocalStorage();
authSessionDestroy();
}
if (_mediaView) {
hideMediaView();
_mediaView->clearData();
}
Local::reset();
cSetOtherOnline(0);
Images::ClearRemote();
}
QPoint Application::getPointForCallPanelCenter() const {
if (const auto window = activeWindow()) {
return window->getPointForCallPanelCenter();

View File

@ -120,34 +120,16 @@ public:
MTP::DcOptions *dcOptions() {
return _dcOptions.get();
}
struct ProxyChange {
ProxyData was;
ProxyData now;
};
void setCurrentProxy(
const ProxyData &proxy,
ProxyData::Settings settings);
[[nodiscard]] rpl::producer<ProxyChange> proxyChanges() const;
void badMtprotoConfigurationError();
// Set from legacy storage.
void setMtpMainDcId(MTP::DcId mainDcId);
void setMtpKey(MTP::DcId dcId, const MTP::AuthKey::Data &keyData);
void setAuthSessionUserId(UserId userId);
void setAuthSessionFromStorage(
std::unique_ptr<AuthSessionSettings> data,
QByteArray &&selfSerialized,
int32 selfStreamVersion);
AuthSessionSettings *getAuthSessionSettings();
// Serialization.
QByteArray serializeMtpAuthorization() const;
void setMtpAuthorization(const QByteArray &serialized);
void startMtp();
MTP::Instance *mtp() {
return _mtproto.get();
}
void suggestMainDcId(MTP::DcId mainDcId);
void destroyStaleAuthorizationKeys();
void configUpdated();
[[nodiscard]] rpl::producer<> configUpdates() const;
// Databases.
Storage::Databases &databases() {
return *_databases;
@ -159,10 +141,8 @@ public:
}
// AuthSession component.
void authSessionCreate(const MTPUser &user);
int unreadBadge() const;
bool unreadBadgeMuted() const;
void logOut();
// Media component.
Media::Audio::Instance &audio() {
@ -244,9 +224,6 @@ private:
friend bool IsAppLaunched();
friend Application &App();
void destroyMtpKeys(MTP::AuthKeysList &&keys);
void allKeysDestroyed();
void startLocalStorage();
void startShortcuts();
@ -256,14 +233,20 @@ private:
static void QuitAttempt();
void quitDelayed();
void resetAuthorizationKeys();
void authSessionDestroy();
void clearPasscodeLock();
void loggedOut();
static Application *Instance;
struct InstanceSetter {
InstanceSetter(not_null<Application*> instance) {
Expects(Instance == nullptr);
Instance = instance;
}
};
InstanceSetter _setter = { this };
not_null<Launcher*> _launcher;
rpl::event_stream<ProxyChange> _proxyChanges;
// Some fields are just moved from the declaration.
struct Private;
@ -273,6 +256,7 @@ private:
const std::unique_ptr<Storage::Databases> _databases;
const std::unique_ptr<Ui::Animations::Manager> _animationsManager;
const std::unique_ptr<MTP::DcOptions> _dcOptions;
const std::unique_ptr<Main::Account> _account;
std::unique_ptr<Window::Controller> _window;
std::unique_ptr<Media::View::OverlayWidget> _mediaView;
@ -280,10 +264,6 @@ private:
std::unique_ptr<Lang::CloudManager> _langCloudManager;
const std::unique_ptr<ChatHelpers::EmojiKeywords> _emojiKeywords;
std::unique_ptr<Lang::Translator> _translator;
std::unique_ptr<MTP::DcOptions> _dcOptions;
std::unique_ptr<MTP::Instance> _mtproto;
std::unique_ptr<MTP::Instance> _mtprotoForKeysDestroy;
rpl::event_stream<> _configUpdates;
base::Observable<void> _passcodedChanged;
QPointer<BoxContent> _badProxyDisableBox;

View File

@ -13,8 +13,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/unixtime.h"
#include "storage/localstorage.h"
#include "core/application.h"
#include "mainwindow.h"
#include "core/click_handler_types.h"
#include "mainwindow.h"
#include "main/main_account.h"
#include "info/info_memento.h"
#include "info/settings/info_settings_widget.h"
#include "window/window_session_controller.h"
@ -1390,7 +1391,7 @@ Updater::~Updater() {
UpdateChecker::UpdateChecker()
: _updater(GetUpdaterInstance()) {
if (IsAppLaunched()) {
if (const auto mtproto = Core::App().mtp()) {
if (const auto mtproto = Core::App().activeAccount().mtp()) {
_updater->setMtproto(mtproto);
}
}

View File

@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "lang/lang_keys.h"
#include "storage/storage_facade.h"
#include "core/application.h"
#include "main/main_account.h"
//#include "storage/storage_feed_messages.h" // #feed
#include "auth_session.h"
#include "observer_peer.h"
@ -28,11 +29,12 @@ namespace {
constexpr auto kLoadedChatsMinCount = 20;
constexpr auto kShowChatNamesCount = 8;
rpl::producer<int> PinnedDialogsInFolderMaxValue() {
rpl::producer<int> PinnedDialogsInFolderMaxValue(
not_null<AuthSession*> session) {
return rpl::single(
rpl::empty_value()
) | rpl::then(
Core::App().configUpdates()
session->account().configUpdates()
) | rpl::map([=] {
return Global::PinnedDialogsInFolderMax();
});
@ -53,7 +55,7 @@ rpl::producer<int> PinnedDialogsInFolderMaxValue() {
Folder::Folder(not_null<Data::Session*> owner, FolderId id)
: Entry(owner, this)
, _id(id)
, _chatsList(PinnedDialogsInFolderMaxValue())
, _chatsList(PinnedDialogsInFolderMaxValue(&owner->session()))
, _name(tr::lng_archived_name(tr::now)) {
indexNameParts();

View File

@ -25,6 +25,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "inline_bots/inline_bot_layout_item.h"
#include "storage/localstorage.h"
#include "storage/storage_encrypted_file.h"
#include "main/main_account.h"
#include "media/player/media_player_instance.h" // instance()->play()
#include "media/streaming/media_streaming_loader.h" // unique_ptr<Loader>
#include "media/streaming/media_streaming_reader.h" // make_shared<Reader>
@ -155,11 +156,12 @@ MTPPhotoSize FindDocumentThumbnail(const MTPDdocument &data) {
: MTPPhotoSize(MTP_photoSizeEmpty(MTP_string()));
}
rpl::producer<int> PinnedDialogsCountMaxValue() {
rpl::producer<int> PinnedDialogsCountMaxValue(
not_null<AuthSession*> session) {
return rpl::single(
rpl::empty_value()
) | rpl::then(
Core::App().configUpdates()
session->account().configUpdates()
) | rpl::map([=] {
return Global::PinnedDialogsCountMax();
});
@ -195,7 +197,7 @@ Session::Session(not_null<AuthSession*> session)
, _bigFileCache(Core::App().databases().get(
Local::cacheBigFilePath(),
Local::cacheBigFileSettings()))
, _chatsList(PinnedDialogsCountMaxValue())
, _chatsList(PinnedDialogsCountMaxValue(session))
, _contactsList(Dialogs::SortMode::Name)
, _contactsNoChatsList(Dialogs::SortMode::Name)
, _selfDestructTimer([=] { checkSelfDestructItems(); })

View File

@ -73,7 +73,11 @@ void CodeInput::correctValue(const QString &was, int wasCursor, QString &now, in
}
}
CodeWidget::CodeWidget(QWidget *parent, Widget::Data *data) : Step(parent, data)
CodeWidget::CodeWidget(
QWidget *parent,
not_null<Main::Account*> account,
not_null<Widget::Data*> data)
: Step(parent, account, data)
, _noTelegramCode(this, tr::lng_code_no_telegram(tr::now), st::introLink)
, _code(this, st::introCode, tr::lng_code_ph())
, _callTimer(this)
@ -244,7 +248,7 @@ void CodeWidget::codeSubmitDone(const MTPauth_Authorization &result) {
} else {
getData()->termsLock = Window::TermsLock();
}
goReplace(new Intro::SignupWidget(parentWidget(), getData()));
goReplace<SignupWidget>();
});
}
@ -342,7 +346,7 @@ void CodeWidget::gotPassword(const MTPaccount_Password &result) {
getData()->hasRecovery = d.is_has_recovery();
getData()->pwdHint = qs(d.vhint().value_or_empty());
getData()->pwdNotEmptyPassport = d.is_has_secure_values();
goReplace(new Intro::PwdCheckWidget(parentWidget(), getData()));
goReplace<PwdCheckWidget>();
}
void CodeWidget::submit() {

View File

@ -39,7 +39,10 @@ class CodeWidget : public Widget::Step {
Q_OBJECT
public:
CodeWidget(QWidget *parent, Widget::Data *data);
CodeWidget(
QWidget *parent,
not_null<Main::Account*> account,
not_null<Widget::Data*> data);
bool hasBack() const override {
return true;

View File

@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/buttons.h"
#include "ui/widgets/labels.h"
#include "ui/wrap/fade_wrap.h"
#include "main/main_account.h"
#include "boxes/confirm_phone_box.h"
#include "boxes/confirm_box.h"
#include "core/application.h"
@ -29,7 +30,11 @@ bool AllowPhoneAttempt(const QString &phone) {
} // namespace
PhoneWidget::PhoneWidget(QWidget *parent, Widget::Data *data) : Step(parent, data)
PhoneWidget::PhoneWidget(
QWidget *parent,
not_null<Main::Account*> account,
not_null<Widget::Data*> data)
: Step(parent, account, data)
, _country(this, st::introCountry)
, _code(this, st::introCountryCode)
, _phone(this, st::introPhone)
@ -54,7 +59,7 @@ PhoneWidget::PhoneWidget(QWidget *parent, Widget::Data *data) : Step(parent, dat
}
_changed = false;
Core::App().destroyStaleAuthorizationKeys();
account->destroyStaleAuthorizationKeys();
}
void PhoneWidget::resizeEvent(QResizeEvent *e) {
@ -111,7 +116,7 @@ void PhoneWidget::submit() {
_checkRequest->start(1000);
_sentPhone = phone;
Core::App().mtp()->setUserPhone(_sentPhone);
account().mtp()->setUserPhone(_sentPhone);
_sentRequest = MTP::send(
MTPauth_SendCode(
MTP_string(_sentPhone),
@ -162,7 +167,7 @@ void PhoneWidget::phoneSubmitDone(const MTPauth_SentCode &result) {
getData()->callStatus = Widget::Data::CallStatus::Disabled;
getData()->callTimeout = 0;
}
goNext(new Intro::CodeWidget(parentWidget(), getData()));
goNext<CodeWidget>();
}
bool PhoneWidget::phoneSubmitFail(const RPCError &error) {

View File

@ -23,7 +23,10 @@ class PhoneWidget : public Widget::Step {
Q_OBJECT
public:
PhoneWidget(QWidget *parent, Widget::Data *data);
PhoneWidget(
QWidget *parent,
not_null<Main::Account*> account,
not_null<Widget::Data*> data);
void selectCountry(const QString &country);

View File

@ -23,8 +23,9 @@ namespace Intro {
PwdCheckWidget::PwdCheckWidget(
QWidget *parent,
Widget::Data *data)
: Step(parent, data)
not_null<Main::Account*> account,
not_null<Widget::Data*> data)
: Step(parent, account, data)
, _request(getData()->pwdRequest)
, _hasRecovery(getData()->hasRecovery)
, _notEmptyPassport(getData()->pwdNotEmptyPassport)

View File

@ -23,7 +23,10 @@ class PwdCheckWidget : public Widget::Step, private MTP::Sender {
Q_OBJECT
public:
PwdCheckWidget(QWidget *parent, Widget::Data *data);
PwdCheckWidget(
QWidget *parent,
not_null<Main::Account*> account,
not_null<Widget::Data*> data);
void setInnerFocus() override;
void activate() override;

View File

@ -20,7 +20,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace Intro {
SignupWidget::SignupWidget(QWidget *parent, Widget::Data *data) : Step(parent, data)
SignupWidget::SignupWidget(
QWidget *parent,
not_null<Main::Account*> account,
not_null<Widget::Data*> data)
: Step(parent, account, data)
, _photo(
this,
tr::lng_settings_crop_profile(tr::now),

View File

@ -21,7 +21,10 @@ class SignupWidget : public Widget::Step {
Q_OBJECT
public:
SignupWidget(QWidget *parent, Widget::Data *data);
SignupWidget(
QWidget *parent,
not_null<Main::Account*> account,
not_null<Widget::Data*> data);
void finishInit() override;
void setInnerFocus() override;

View File

@ -14,7 +14,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace Intro {
StartWidget::StartWidget(QWidget *parent, Widget::Data *data) : Step(parent, data, true) {
StartWidget::StartWidget(
QWidget *parent,
not_null<Main::Account*> account,
not_null<Widget::Data*> data)
: Step(parent, account, data, true) {
setMouseTracking(true);
setTitleText(rpl::single(qsl("Telegram Desktop")));
setDescriptionText(tr::lng_intro_about());
@ -22,7 +26,7 @@ StartWidget::StartWidget(QWidget *parent, Widget::Data *data) : Step(parent, dat
}
void StartWidget::submit() {
goNext(new Intro::PhoneWidget(parentWidget(), getData()));
goNext<PhoneWidget>();
}
rpl::producer<QString> StartWidget::nextButtonText() const {

View File

@ -19,7 +19,10 @@ namespace Intro {
class StartWidget : public Widget::Step {
public:
StartWidget(QWidget *parent, Widget::Data *data);
StartWidget(
QWidget *parent,
not_null<Main::Account*> account,
not_null<Widget::Data*> data);
void submit() override;
rpl::producer<QString> nextButtonText() const override;

View File

@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "intro/introcode.h"
#include "intro/introsignup.h"
#include "intro/intropwdcheck.h"
#include "main/main_account.h"
#include "mainwidget.h"
#include "apiwrap.h"
#include "mainwindow.h"
@ -59,7 +60,9 @@ void PrepareSupportMode() {
} // namespace
Widget::Widget(QWidget *parent) : RpWidget(parent)
Widget::Widget(QWidget *parent, not_null<Main::Account*> account)
: RpWidget(parent)
, _account(account)
, _back(this, object_ptr<Ui::IconButton>(this, st::introBackButton))
, _settings(
this,
@ -84,7 +87,7 @@ Widget::Widget(QWidget *parent) : RpWidget(parent)
getNearestDC();
setupConnectingWidget();
appendStep(new StartWidget(this, getData()));
appendStep(new StartWidget(this, _account, getData()));
fixOrder();
subscribe(Lang::CurrentCloudManager().firstLanguageSuggestion(), [this] { createLanguageLink(); });
@ -367,11 +370,13 @@ void Widget::resetAccount() {
_resetRequest = 0;
Ui::hideLayer();
moveToStep(new SignupWidget(this, getData()), Direction::Replace);
moveToStep(
new SignupWidget(this, _account, getData()),
Direction::Replace);
}).fail([this](const RPCError &error) {
_resetRequest = 0;
auto type = error.type();
const auto &type = error.type();
if (type.startsWith(qstr("2FA_CONFIRM_WAIT_"))) {
const auto seconds = type.mid(qstr("2FA_CONFIRM_WAIT_").size()).toInt();
const auto days = (seconds + 59) / 86400;
@ -434,7 +439,7 @@ void Widget::getNearestDC() {
).arg(qs(nearest.vcountry())
).arg(nearest.vnearest_dc().v
).arg(nearest.vthis_dc().v));
Core::App().suggestMainDcId(nearest.vnearest_dc().v);
_account->suggestMainDcId(nearest.vnearest_dc().v);
auto nearestCountry = qs(nearest.vcountry());
if (getData()->country != nearestCountry) {
getData()->country = nearestCountry;
@ -664,16 +669,19 @@ void Widget::Step::finish(const MTPUser &user, QImage &&photo) {
Local::writeLangPack();
}
Core::App().authSessionCreate(user);
const auto account = _account;
const auto weak = base::make_weak(account.get());
account->createSession(user);
Local::writeMtpData();
App::wnd()->setupMain();
// "this" is already deleted here by creating the main widget.
if (AuthSession::Exists()) {
if (weak && account->sessionExists()) {
auto &session = account->session();
if (!photo.isNull()) {
Auth().api().uploadPeerPhoto(Auth().user(), std::move(photo));
session.api().uploadPeerPhoto(session.user(), std::move(photo));
}
if (Auth().supportMode()) {
if (session.supportMode()) {
PrepareSupportMode();
}
}
@ -919,8 +927,13 @@ void Widget::Step::refreshError(const QString &text) {
}
}
Widget::Step::Step(QWidget *parent, Data *data, bool hasCover)
Widget::Step::Step(
QWidget *parent,
not_null<Main::Account*> account,
not_null<Data*> data,
bool hasCover)
: RpWidget(parent)
, _account(account)
, _data(data)
, _hasCover(hasCover)
, _title(this, _hasCover ? st::introCoverTitle : st::introTitle)

View File

@ -13,6 +13,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "window/window_lock_widgets.h"
#include "core/core_cloud_password.h"
namespace Main {
class Account;
} // namespace Main
namespace Ui {
class IconButton;
class RoundButton;
@ -34,7 +38,7 @@ class Widget : public Ui::RpWidget, private MTP::Sender, private base::Subscribe
Q_OBJECT
public:
Widget(QWidget *parent);
Widget(QWidget *parent, not_null<Main::Account*> account);
void showAnimated(const QPixmap &bgAnimCache, bool back = false);
@ -90,7 +94,15 @@ public:
};
class Step : public Ui::RpWidget, public RPCSender, protected base::Subscriber {
public:
Step(QWidget *parent, Data *data, bool hasCover = false);
Step(
QWidget *parent,
not_null<Main::Account*> account,
not_null<Data*> data,
bool hasCover = false);
Main::Account &account() const {
return *_account;
}
virtual void finishInit() {
}
@ -147,19 +159,33 @@ public:
void showDescription();
void hideDescription();
Data *getData() const {
not_null<Data*> getData() const {
return _data;
}
void finish(const MTPUser &user, QImage &&photo = QImage());
void goBack() {
if (_goCallback) _goCallback(nullptr, Direction::Back);
if (_goCallback) {
_goCallback(nullptr, Direction::Back);
}
}
void goNext(Step *step) {
if (_goCallback) _goCallback(step, Direction::Forward);
template <typename StepType>
void goNext() {
if (_goCallback) {
_goCallback(
new StepType(parentWidget(), _account, _data),
Direction::Forward);
}
}
void goReplace(Step *step) {
if (_goCallback) _goCallback(step, Direction::Replace);
template <typename StepType>
void goReplace() {
if (_goCallback) {
_goCallback(
new StepType(parentWidget(), _account, _data),
Direction::Replace);
}
}
void showResetButton() {
if (_showResetCallback) _showResetCallback();
@ -190,9 +216,6 @@ public:
void updateLabelsPosition();
void paintContentSnapshot(Painter &p, const QPixmap &snapshot, float64 alpha, float64 howMuchHidden);
void refreshError(const QString &text);
void refreshTitle();
void refreshDescription();
void refreshLang();
CoverAnimation prepareCoverAnimation(Step *step);
QPixmap prepareContentSnapshot();
@ -202,7 +225,9 @@ public:
void prepareCoverMask();
void paintCover(Painter &p, int top);
Data *_data = nullptr;
const not_null<Main::Account*> _account;
const not_null<Data*> _data;
bool _hasCover = false;
Fn<void(Step *step, Direction direction)> _goCallback;
Fn<void()> _showResetCallback;
@ -233,7 +258,7 @@ private:
void createLanguageLink();
void updateControlsGeometry();
Data *getData() {
not_null<Data*> getData() {
return &_data;
}
@ -260,6 +285,8 @@ private:
void getNearestDC();
void showTerms(Fn<void()> callback);
not_null<Main::Account*> _account;
Ui::Animations::Simple _a_show;
bool _showBack = false;
QPixmap _cacheUnder, _cacheOver;

View File

@ -7,28 +7,113 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "main/main_account.h"
#include "auth_session.h"
#include "core/application.h"
#include "core/launcher.h"
#include "core/shortcuts.h"
#include "storage/serialize_common.h"
#include "storage/localstorage.h"
#include "data/data_session.h"
#include "data/data_user.h"
#include "window/window_controller.h"
#include "media/audio/media_audio.h"
#include "mainwidget.h"
#include "observer_peer.h"
#include "auth_session.h"
namespace Main {
Account::Account(const QString &dataName) {
watchProxyChanges();
watchSessionChanges();
}
Account::~Account() {
Account::~Account() = default;
void Account::watchProxyChanges() {
using ProxyChange = Core::Application::ProxyChange;
Core::App().proxyChanges(
) | rpl::start_with_next([=](const ProxyChange &change) {
const auto key = [&](const ProxyData &proxy) {
return (proxy.type == ProxyData::Type::Mtproto)
? std::make_pair(proxy.host, proxy.port)
: std::make_pair(QString(), uint32(0));
};
if (_mtp) {
_mtp->restart();
if (key(change.was) != key(change.now)) {
_mtp->reInitConnection(_mtp->mainDcId());
}
}
if (_mtpForKeysDestroy) {
_mtpForKeysDestroy->restart();
}
}, _lifetime);
}
void Account::watchSessionChanges() {
sessionChanges(
) | rpl::start_with_next([=] {
crl::on_main(this, [=] {
const auto phone = sessionExists()
? session().user()->phone()
: QString();
const auto support = sessionExists() && session().supportMode();
if (cLoggedPhoneNumber() != phone) {
cSetLoggedPhoneNumber(phone);
if (_mtp) {
_mtp->setUserPhone(phone);
}
Local::writeSettings();
}
if (_mtp) {
_mtp->requestConfig();
}
Shortcuts::ToggleSupportShortcuts(support);
Platform::SetApplicationIcon(Window::CreateIcon(this));
});
}, _lifetime);
}
void Account::createSession(const MTPUser &user) {
Expects(_mtp != nullptr);
Expects(_session == nullptr);
Expects(_sessionValue.current() == nullptr);
_mtp->setUpdatesHandler(::rpcDone([](
const mtpPrime *from,
const mtpPrime *end) {
if (const auto main = App::main()) {
return main->updateReceived(from, end);
}
return true;
}));
_mtp->setGlobalFailHandler(::rpcFail([=](const RPCError &error) {
if (sessionExists()) {
crl::on_main(&session(), [=] { logOut(); });
}
return true;
}));
_session = std::make_unique<AuthSession>(this, user);
_sessionValue = _session.get();
}
void Account::destroySession() {
_storedAuthSession.reset();
_authSessionUserId = 0;
_authSessionUserSerialized = {};
if (!sessionExists()) {
return;
}
session().data().clearLocalStorage();
_mtp->clearGlobalHandlers();
_sessionValue = nullptr;
_session = nullptr;
Notify::unreadCounterUpdated();
}
bool Account::sessionExists() const {
@ -41,6 +126,12 @@ AuthSession &Account::session() {
return *_sessionValue.current();
}
const AuthSession &Account::session() const {
Expects(sessionExists());
return *_sessionValue.current();
}
rpl::producer<AuthSession*> Account::sessionValue() const {
return _sessionValue.value();
}
@ -49,8 +140,343 @@ rpl::producer<AuthSession*> Account::sessionChanges() const {
return _sessionValue.changes();
}
MTP::Instance *Account::mtp() {
return MTP::MainInstance();
rpl::producer<MTP::Instance*> Account::mtpValue() const {
return _mtpValue.value();
}
rpl::producer<MTP::Instance*> Account::mtpChanges() const {
return _mtpValue.changes();
}
void Account::setMtpMainDcId(MTP::DcId mainDcId) {
Expects(!_mtp);
_mtpConfig.mainDcId = mainDcId;
}
void Account::setMtpKey(MTP::DcId dcId, const MTP::AuthKey::Data &keyData) {
Expects(!_mtp);
_mtpConfig.keys.push_back(std::make_shared<MTP::AuthKey>(
MTP::AuthKey::Type::ReadFromFile,
dcId,
keyData));
}
QByteArray Account::serializeMtpAuthorization() const {
const auto serialize = [&](
MTP::DcId mainDcId,
const MTP::AuthKeysList &keys,
const MTP::AuthKeysList &keysToDestroy) {
const auto keysSize = [](auto &list) {
const auto keyDataSize = MTP::AuthKey::Data().size();
return sizeof(qint32)
+ list.size() * (sizeof(qint32) + keyDataSize);
};
const auto writeKeys = [](
QDataStream &stream,
const MTP::AuthKeysList &keys) {
stream << qint32(keys.size());
for (const auto &key : keys) {
stream << qint32(key->dcId());
key->write(stream);
}
};
auto result = QByteArray();
auto size = sizeof(qint32) + sizeof(qint32); // userId + mainDcId
size += keysSize(keys) + keysSize(keysToDestroy);
result.reserve(size);
{
QDataStream stream(&result, QIODevice::WriteOnly);
stream.setVersion(QDataStream::Qt_5_1);
const auto currentUserId = sessionExists()
? session().userId()
: 0;
stream << qint32(currentUserId) << qint32(mainDcId);
writeKeys(stream, keys);
writeKeys(stream, keysToDestroy);
DEBUG_LOG(("MTP Info: Keys written, userId: %1, dcId: %2").arg(currentUserId).arg(mainDcId));
}
return result;
};
if (_mtp) {
const auto keys = _mtp->getKeysForWrite();
const auto keysToDestroy = _mtpForKeysDestroy
? _mtpForKeysDestroy->getKeysForWrite()
: MTP::AuthKeysList();
return serialize(_mtp->mainDcId(), keys, keysToDestroy);
}
const auto &keys = _mtpConfig.keys;
const auto &keysToDestroy = _mtpKeysToDestroy;
return serialize(_mtpConfig.mainDcId, keys, keysToDestroy);
}
void Account::setAuthSessionUserId(UserId userId) {
Expects(!sessionExists());
_authSessionUserId = userId;
}
void Account::setAuthSessionFromStorage(
std::unique_ptr<AuthSessionSettings> data,
QByteArray &&selfSerialized,
int32 selfStreamVersion) {
Expects(!sessionExists());
DEBUG_LOG(("authSessionUserSerialized set: %1"
).arg(selfSerialized.size()));
_storedAuthSession = std::move(data);
_authSessionUserSerialized = std::move(selfSerialized);
_authSessionUserStreamVersion = selfStreamVersion;
}
AuthSessionSettings *Account::getAuthSessionSettings() {
if (_authSessionUserId) {
return _storedAuthSession ? _storedAuthSession.get() : nullptr;
} else if (sessionExists()) {
return &session().settings();
}
return nullptr;
}
void Account::setMtpAuthorization(const QByteArray &serialized) {
Expects(!_mtp);
QDataStream stream(serialized);
stream.setVersion(QDataStream::Qt_5_1);
auto userId = Serialize::read<qint32>(stream);
auto mainDcId = Serialize::read<qint32>(stream);
if (stream.status() != QDataStream::Ok) {
LOG(("MTP Error: "
"Could not read main fields from mtp authorization."));
return;
}
setAuthSessionUserId(userId);
_mtpConfig.mainDcId = mainDcId;
const auto readKeys = [&stream](auto &keys) {
const auto count = Serialize::read<qint32>(stream);
if (stream.status() != QDataStream::Ok) {
LOG(("MTP Error: "
"Could not read keys count from mtp authorization."));
return;
}
keys.reserve(count);
for (auto i = 0; i != count; ++i) {
const auto dcId = Serialize::read<qint32>(stream);
const auto keyData = Serialize::read<MTP::AuthKey::Data>(stream);
if (stream.status() != QDataStream::Ok) {
LOG(("MTP Error: "
"Could not read key from mtp authorization."));
return;
}
keys.push_back(std::make_shared<MTP::AuthKey>(MTP::AuthKey::Type::ReadFromFile, dcId, keyData));
}
};
readKeys(_mtpConfig.keys);
readKeys(_mtpKeysToDestroy);
LOG(("MTP Info: "
"read keys, current: %1, to destroy: %2"
).arg(_mtpConfig.keys.size()
).arg(_mtpKeysToDestroy.size()));
}
void Account::startMtp() {
Expects(!_mtp);
auto config = base::take(_mtpConfig);
config.deviceModel = Core::App().launcher()->deviceModel();
config.systemVersion = Core::App().launcher()->systemVersion();
_mtp = std::make_unique<MTP::Instance>(
Core::App().dcOptions(),
MTP::Instance::Mode::Normal,
std::move(config));
_mtp->setUserPhone(cLoggedPhoneNumber());
_mtpConfig.mainDcId = _mtp->mainDcId();
_mtp->setStateChangedHandler([](MTP::ShiftedDcId dc, int32 state) {
if (dc == MTP::maindc()) {
Global::RefConnectionTypeChanged().notify();
}
});
_mtp->setSessionResetHandler([](MTP::ShiftedDcId shiftedDcId) {
if (App::main() && shiftedDcId == MTP::maindc()) {
App::main()->getDifference();
}
});
if (!_mtpKeysToDestroy.empty()) {
destroyMtpKeys(base::take(_mtpKeysToDestroy));
}
if (_authSessionUserId) {
DEBUG_LOG(("authSessionUserSerialized.size: %1"
).arg(_authSessionUserSerialized.size()));
QDataStream peekStream(_authSessionUserSerialized);
const auto phone = Serialize::peekUserPhone(
_authSessionUserStreamVersion,
peekStream);
const auto flags = MTPDuser::Flag::f_self | (phone.isEmpty()
? MTPDuser::Flag()
: MTPDuser::Flag::f_phone);
createSession(MTP_user(
MTP_flags(flags),
MTP_int(base::take(_authSessionUserId)),
MTPlong(), // access_hash
MTPstring(), // first_name
MTPstring(), // last_name
MTPstring(), // username
MTP_string(phone),
MTPUserProfilePhoto(),
MTPUserStatus(),
MTPint(), // bot_info_version
MTPstring(), // restriction_reason
MTPstring(), // bot_inline_placeholder
MTPstring())); // lang_code
Local::readSelf(
base::take(_authSessionUserSerialized),
base::take(_authSessionUserStreamVersion));
}
if (_storedAuthSession) {
if (sessionExists()) {
session().moveSettingsFrom(std::move(*_storedAuthSession));
}
_storedAuthSession.reset();
}
if (sessionExists()) {
// Skip all pending self updates so that we won't Local::writeSelf.
Notify::peerUpdatedSendDelayed();
}
_mtpValue = _mtp.get();
}
void Account::logOut() {
if (_mtp) {
_mtp->logout(::rpcDone([=] {
loggedOut();
}), ::rpcFail([=] {
loggedOut();
return true;
}));
} else {
// We log out because we've forgotten passcode.
// So we just start mtproto from scratch.
startMtp();
loggedOut();
}
}
void Account::forcedLogOut() {
if (sessionExists()) {
resetAuthorizationKeys();
loggedOut();
}
}
void Account::loggedOut() {
if (Global::LocalPasscode()) {
Global::SetLocalPasscode(false);
Global::RefLocalPasscodeChanged().notify();
}
Core::App().unlockPasscode();
Core::App().unlockTerms();
Media::Player::mixer()->stopAndClear();
Global::SetVoiceMsgPlaybackDoubled(false);
if (const auto window = Core::App().activeWindow()) {
window->tempDirDelete(Local::ClearManagerAll);
window->setupIntro();
}
destroySession();
Local::reset();
cSetOtherOnline(0);
Images::ClearRemote();
}
void Account::destroyMtpKeys(MTP::AuthKeysList &&keys) {
if (keys.empty()) {
return;
}
if (_mtpForKeysDestroy) {
_mtpForKeysDestroy->addKeysForDestroy(std::move(keys));
Local::writeMtpData();
return;
}
auto destroyConfig = MTP::Instance::Config();
destroyConfig.mainDcId = MTP::Instance::Config::kNoneMainDc;
destroyConfig.keys = std::move(keys);
destroyConfig.deviceModel = Core::App().launcher()->deviceModel();
destroyConfig.systemVersion = Core::App().launcher()->systemVersion();
_mtpForKeysDestroy = std::make_unique<MTP::Instance>(
Core::App().dcOptions(),
MTP::Instance::Mode::KeysDestroyer,
std::move(destroyConfig));
QObject::connect(
_mtpForKeysDestroy.get(),
&MTP::Instance::allKeysDestroyed,
[=] { allKeysDestroyed(); });
}
void Account::allKeysDestroyed() {
LOG(("MTP Info: all keys scheduled for destroy are destroyed."));
crl::on_main(this, [=] {
_mtpForKeysDestroy = nullptr;
Local::writeMtpData();
});
}
void Account::suggestMainDcId(MTP::DcId mainDcId) {
Expects(_mtp != nullptr);
_mtp->suggestMainDcId(mainDcId);
if (_mtpConfig.mainDcId != MTP::Instance::Config::kNotSetMainDc) {
_mtpConfig.mainDcId = mainDcId;
}
}
void Account::destroyStaleAuthorizationKeys() {
Expects(_mtp != nullptr);
for (const auto &key : _mtp->getKeysForWrite()) {
// Disable this for now.
if (key->type() == MTP::AuthKey::Type::ReadFromFile) {
_mtpKeysToDestroy = _mtp->getKeysForWrite();
LOG(("MTP Info: destroying stale keys, count: %1"
).arg(_mtpKeysToDestroy.size()));
resetAuthorizationKeys();
return;
}
}
}
void Account::configUpdated() {
_configUpdates.fire({});
}
rpl::producer<> Account::configUpdates() const {
return _configUpdates.events();
}
void Account::resetAuthorizationKeys() {
_mtp = nullptr;
_mtpValue = _mtp.get();
startMtp();
Local::writeMtpData();
}
void Account::clearMtp() {
_mtp = nullptr;
_mtpForKeysDestroy = nullptr;
_mtpValue = _mtp.get();
}
} // namespace Main

View File

@ -7,11 +7,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "mtproto/auth_key.h"
#include "base/weak_ptr.h"
class AuthSession;
class AuthSessionSettings;
namespace Main {
class Account final {
class Account final : public base::has_weak_ptr {
public:
explicit Account(const QString &dataName);
~Account();
@ -22,17 +26,69 @@ public:
void createSession(const MTPUser &user);
void destroySession();
void logOut();
void forcedLogOut();
[[nodiscard]] bool sessionExists() const;
[[nodiscard]] AuthSession &session();
[[nodiscard]] const AuthSession &session() const;
[[nodiscard]] rpl::producer<AuthSession*> sessionValue() const;
[[nodiscard]] rpl::producer<AuthSession*> sessionChanges() const;
[[nodiscard]] MTP::Instance *mtp();
[[nodiscard]] MTP::Instance *mtp() {
return _mtp.get();
}
[[nodiscard]] rpl::producer<MTP::Instance*> mtpValue() const;
[[nodiscard]] rpl::producer<MTP::Instance*> mtpChanges() const;
// Set from legacy storage.
void setMtpMainDcId(MTP::DcId mainDcId);
void setMtpKey(MTP::DcId dcId, const MTP::AuthKey::Data &keyData);
void setAuthSessionUserId(UserId userId);
void setAuthSessionFromStorage(
std::unique_ptr<AuthSessionSettings> data,
QByteArray &&selfSerialized,
int32 selfStreamVersion);
[[nodiscard]] AuthSessionSettings *getAuthSessionSettings();
// Serialization.
[[nodiscard]] QByteArray serializeMtpAuthorization() const;
void setMtpAuthorization(const QByteArray &serialized);
void startMtp();
void suggestMainDcId(MTP::DcId mainDcId);
void destroyStaleAuthorizationKeys();
void configUpdated();
[[nodiscard]] rpl::producer<> configUpdates() const;
void clearMtp();
private:
void watchProxyChanges();
void watchSessionChanges();
void destroyMtpKeys(MTP::AuthKeysList &&keys);
void allKeysDestroyed();
void resetAuthorizationKeys();
void loggedOut();
std::unique_ptr<MTP::Instance> _mtp;
rpl::variable<MTP::Instance*> _mtpValue;
std::unique_ptr<MTP::Instance> _mtpForKeysDestroy;
rpl::event_stream<> _configUpdates;
std::unique_ptr<AuthSession> _session;
rpl::variable<AuthSession*> _sessionValue;
UserId _authSessionUserId = 0;
QByteArray _authSessionUserSerialized;
int32 _authSessionUserStreamVersion = 0;
std::unique_ptr<AuthSessionSettings> _storedAuthSession;
MTP::Instance::Config _mtpConfig;
MTP::AuthKeysList _mtpKeysToDestroy;
rpl::lifetime _lifetime;
};
} // namespace Main

View File

@ -4244,7 +4244,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
} break;
case mtpc_updateConfig: {
Core::App().mtp()->requestConfig();
session().mtp()->requestConfig();
} break;
case mtpc_updateUserPhone: {

View File

@ -200,7 +200,7 @@ void MainWindow::clearPasscodeLock() {
_main->showAnimated(bg, true);
Core::App().checkStartUrl();
} else {
Core::App().startMtp();
account().startMtp();
if (account().sessionExists()) {
setupMain();
} else {
@ -216,7 +216,7 @@ void MainWindow::setupIntro() {
auto bg = animated ? grabInner() : QPixmap();
clearWidgets();
_intro.create(bodyWidget());
_intro.create(bodyWidget(), &account());
updateControlsGeometry();
if (animated) {
@ -619,16 +619,15 @@ void MainWindow::onLogout() {
showFromTray();
}
const auto logout = [] {
Core::App().logOut();
};
const auto callback = [=] {
if (account().sessionExists()
&& account().session().data().exportInProgress()) {
Ui::hideLayer();
account().session().data().stopExportWithConfirmation(logout);
account().session().data().stopExportWithConfirmation([=] {
account().logOut();
});
} else {
logout();
account().logOut();
}
};
Ui::show(Box<ConfirmBox>(

View File

@ -88,6 +88,10 @@ private:
};
DcOptions::DcOptions() {
constructFromBuiltIn();
}
bool DcOptions::ValidateSecret(bytes::const_span secret) {
// See also TcpConnection::Protocol::Create.
return (secret.size() >= 21 && secret[0] == bytes::type(0xEE))

View File

@ -48,6 +48,8 @@ public:
};
DcOptions();
[[nodiscard]] static bool ValidateSecret(bytes::const_span secret);
// construct methods don't notify "changed" subscribers.

View File

@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "storage/localstorage.h"
#include "core/application.h"
#include "main/main_account.h"
namespace MTP {
namespace internal {
@ -38,7 +39,9 @@ void unpause() {
} // namespace internal
Instance *MainInstance() {
return Core::IsAppLaunched() ? Core::App().mtp() : nullptr;
return Core::IsAppLaunched()
? Core::App().activeAccount().mtp()
: nullptr;
}
} // namespace MTP

View File

@ -17,6 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "mtproto/rsa_public_key.h"
#include "storage/localstorage.h"
#include "calls/calls_instance.h"
#include "main/main_account.h"
#include "auth_session.h"
#include "apiwrap.h"
#include "core/application.h"
@ -167,9 +168,9 @@ private:
void checkDelayedRequests();
not_null<Instance*> _instance;
not_null<DcOptions*> _dcOptions;
Instance::Mode _mode = Instance::Mode::Normal;
const not_null<Instance*> _instance;
const not_null<DcOptions*> _dcOptions;
const Instance::Mode _mode = Instance::Mode::Normal;
DcId _mainDcId = Config::kDefaultMainDc;
bool _mainDcIdForced = false;
@ -808,7 +809,7 @@ void Instance::Private::configLoadDone(const MTPConfig &result) {
data.vlang_pack_version().value_or_empty(),
data.vbase_lang_pack_version().value_or_empty());
Core::App().configUpdated();
Core::App().activeAccount().configUpdated();
if (const auto prefix = data.vautoupdate_url_prefix()) {
Local::writeAutoupdatePrefix(qs(*prefix));

View File

@ -108,7 +108,7 @@ auto GenerateCodes() {
codes.emplace(qsl("endpoints"), [] {
FileDialog::GetOpenPath(Core::App().getFileDialogParent(), "Open DC endpoints", "DC Endpoints (*.tdesktop-endpoints)", [](const FileDialog::OpenResult &result) {
if (!result.paths.isEmpty()) {
if (!Core::App().mtp()->dcOptions()->loadFromFile(result.paths.front())) {
if (!Core::App().dcOptions()->loadFromFile(result.paths.front())) {
Ui::show(Box<InformBox>("Could not load endpoints :( Errors in 'log.txt'."));
}
}

View File

@ -26,6 +26,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "mainwindow.h"
#include "lang/lang_keys.h"
#include "lang/lang_cloud_manager.h"
#include "main/main_account.h"
#include "media/audio/media_audio.h"
#include "mtproto/dc_options.h"
#include "core/application.h"
@ -972,8 +973,8 @@ bool _readSetting(quint32 blockId, QDataStream &stream, int version, ReadSetting
if (!_checkStreamStatus(stream)) return false;
DEBUG_LOG(("MTP Info: user found, dc %1, uid %2").arg(dcId).arg(userId));
Core::App().setMtpMainDcId(dcId);
Core::App().setAuthSessionUserId(userId);
Core::App().activeAccount().setMtpMainDcId(dcId);
Core::App().activeAccount().setAuthSessionUserId(userId);
} break;
case dbiKey: {
@ -982,7 +983,7 @@ bool _readSetting(quint32 blockId, QDataStream &stream, int version, ReadSetting
auto key = Serialize::read<MTP::AuthKey::Data>(stream);
if (!_checkStreamStatus(stream)) return false;
Core::App().setMtpKey(dcId, key);
Core::App().activeAccount().setMtpKey(dcId, key);
} break;
case dbiMtpAuthorization: {
@ -990,7 +991,7 @@ bool _readSetting(quint32 blockId, QDataStream &stream, int version, ReadSetting
stream >> serialized;
if (!_checkStreamStatus(stream)) return false;
Core::App().setMtpAuthorization(serialized);
Core::App().activeAccount().setMtpAuthorization(serialized);
} break;
case dbiAutoStart: {
@ -2034,7 +2035,7 @@ void _writeUserSettings() {
}
auto userDataInstance = StoredAuthSessionCache
? StoredAuthSessionCache.get()
: Core::App().getAuthSessionSettings();
: Core::App().activeAccount().getAuthSessionSettings();
auto userData = userDataInstance
? userDataInstance->serialize()
: QByteArray();
@ -2157,7 +2158,7 @@ void _writeMtpData() {
return;
}
auto mtpAuthorizationSerialized = Core::App().serializeMtpAuthorization();
auto mtpAuthorizationSerialized = Core::App().activeAccount().serializeMtpAuthorization();
quint32 size = sizeof(quint32) + Serialize::bytearraySize(mtpAuthorizationSerialized);
@ -2388,7 +2389,7 @@ ReadMapState _readMap(const QByteArray &pass) {
_readMtpData();
DEBUG_LOG(("selfSerialized set: %1").arg(selfSerialized.size()));
Core::App().setAuthSessionFromStorage(
Core::App().activeAccount().setAuthSessionFromStorage(
std::move(StoredAuthSessionCache),
std::move(selfSerialized),
_oldMapVersion);