From bc144377c0c9d1f108fa19b03dac75475c37f2fd Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 16 Jun 2020 13:40:43 +0400 Subject: [PATCH] Support logout of a secondary account. --- Telegram/SourceFiles/api/api_updates.cpp | 2 +- Telegram/SourceFiles/core/application.cpp | 24 +++- Telegram/SourceFiles/core/application.h | 5 +- Telegram/SourceFiles/data/data_session.cpp | 5 +- Telegram/SourceFiles/main/main_account.cpp | 15 +-- Telegram/SourceFiles/main/main_account.h | 5 + Telegram/SourceFiles/main/main_accounts.cpp | 113 ++++++++++++++---- Telegram/SourceFiles/main/main_accounts.h | 13 +- Telegram/SourceFiles/main/main_session.cpp | 1 + Telegram/SourceFiles/mainwindow.cpp | 23 ++-- Telegram/SourceFiles/mainwindow.h | 3 +- .../platform/linux/main_window_linux.cpp | 8 +- .../platform/mac/main_window_mac.mm | 5 +- .../SourceFiles/settings/settings_common.cpp | 2 +- .../SourceFiles/storage/storage_accounts.cpp | 30 ++--- .../SourceFiles/storage/storage_accounts.h | 10 +- .../SourceFiles/window/window_controller.cpp | 2 +- .../window/window_lock_widgets.cpp | 4 +- 18 files changed, 189 insertions(+), 81 deletions(-) diff --git a/Telegram/SourceFiles/api/api_updates.cpp b/Telegram/SourceFiles/api/api_updates.cpp index af5785424..f2f879beb 100644 --- a/Telegram/SourceFiles/api/api_updates.cpp +++ b/Telegram/SourceFiles/api/api_updates.cpp @@ -1722,7 +1722,7 @@ void Updates::feedUpdate(const MTPUpdate &update) { Api::EntitiesFromMTP(&session(), d.ventities().v) }; if (IsForceLogoutNotification(d)) { - Core::App().forceLogOut(text); + Core::App().forceLogOut(&session().account(), text); } else if (d.is_popup()) { const auto &windows = session().windows(); if (!windows.empty()) { diff --git a/Telegram/SourceFiles/core/application.cpp b/Telegram/SourceFiles/core/application.cpp index 09d5d5e94..249b73cef 100644 --- a/Telegram/SourceFiles/core/application.cpp +++ b/Telegram/SourceFiles/core/application.cpp @@ -451,15 +451,33 @@ void Application::startLocalStorage() { _saveSettingsTimer.setCallback([=] { Local::writeSettings(); }); } -void Application::forceLogOut(const TextWithEntities &explanation) { +void Application::logout(Main::Account *account) { + if (account) { + account->logOut(); + } else { + accounts().resetWithForgottenPasscode(); + + if (Global::LocalPasscode()) { + Global::SetLocalPasscode(false); + Global::RefLocalPasscodeChanged().notify(); + } + Core::App().unlockPasscode(); + Core::App().unlockTerms(); + } +} + +void Application::forceLogOut( + not_null account, + const TextWithEntities &explanation) { const auto box = Ui::show(Box( explanation, tr::lng_passcode_logout(tr::now))); box->setCloseByEscape(false); box->setCloseByOutsideClick(false); + const auto weak = base::make_weak(account.get()); connect(box, &QObject::destroyed, [=] { - crl::on_main(this, [=] { - activeAccount().forcedLogOut(); + crl::on_main(weak, [=] { + account->forcedLogOut(); }); }); } diff --git a/Telegram/SourceFiles/core/application.h b/Telegram/SourceFiles/core/application.h index 42307bab1..95c357049 100644 --- a/Telegram/SourceFiles/core/application.h +++ b/Telegram/SourceFiles/core/application.h @@ -189,7 +189,10 @@ public: bool openLocalUrl(const QString &url, QVariant context); bool openInternalUrl(const QString &url, QVariant context); - void forceLogOut(const TextWithEntities &explanation); + void logout(Main::Account *account = nullptr); + void forceLogOut( + not_null account, + const TextWithEntities &explanation); void checkLocalTime(); void lockByPasscode(); void unlockPasscode(); diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index 1c5798d70..56e5642a0 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -1118,8 +1118,7 @@ void Session::setupUserIsContactViewer() { Session::~Session() { // Optimization: clear notifications before destroying items. _session->notifications().clearAllFast(); - - clear(); + clearLocalStorage(); } template @@ -3840,6 +3839,8 @@ void Session::clearLocalStorage() { _cache->close(); _cache->clear(); + _bigFileCache->close(); + _bigFileCache->clear(); } } // namespace Data diff --git a/Telegram/SourceFiles/main/main_account.cpp b/Telegram/SourceFiles/main/main_account.cpp index dfc7a231a..0b854a474 100644 --- a/Telegram/SourceFiles/main/main_account.cpp +++ b/Telegram/SourceFiles/main/main_account.cpp @@ -170,7 +170,6 @@ void Account::destroySession() { if (!sessionExists()) { return; } - session().data().clear(); _sessionValue = nullptr; _session = nullptr; @@ -442,6 +441,10 @@ void Account::logOut() { } } +bool Account::loggingOut() const { + return _loggingOut; +} + void Account::forcedLogOut() { if (sessionExists()) { resetAuthorizationKeys(); @@ -451,20 +454,10 @@ void Account::forcedLogOut() { void Account::loggedOut() { _loggingOut = false; - 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(); - } - if (sessionExists()) { - session().data().clearLocalStorage(); } destroySession(); local().reset(); diff --git a/Telegram/SourceFiles/main/main_account.h b/Telegram/SourceFiles/main/main_account.h index 3ababab33..be949af7a 100644 --- a/Telegram/SourceFiles/main/main_account.h +++ b/Telegram/SourceFiles/main/main_account.h @@ -50,6 +50,7 @@ public: void logOut(); void forcedLogOut(); + [[nodiscard]] bool loggingOut() const; [[nodiscard]] AppConfig &appConfig() const { Expects(_appConfig != nullptr); @@ -95,6 +96,10 @@ public: [[nodiscard]] rpl::producer<> configUpdates() const; void clearMtp(); + rpl::lifetime &lifetime() { + return _lifetime; + } + private: void createSession( const MTPUser &user, diff --git a/Telegram/SourceFiles/main/main_accounts.cpp b/Telegram/SourceFiles/main/main_accounts.cpp index c65e535fe..519cbe5b8 100644 --- a/Telegram/SourceFiles/main/main_accounts.cpp +++ b/Telegram/SourceFiles/main/main_accounts.cpp @@ -30,34 +30,51 @@ bool Accounts::started() const { Storage::StartResult Accounts::start(const QByteArray &passcode) { Expects(!started()); - auto active = -1; - const auto callback = [&](int index, std::unique_ptr account) { - Expects(account != nullptr); - Expects(!_accounts.contains(index)); - - if (_accounts.empty()) { - active = index; - } - _accounts.emplace(index, std::move(account)); - }; - const auto result = _local->start(passcode, callback); + const auto result = _local->start(passcode); if (result == Storage::StartResult::Success) { - Assert(started()); - - for (const auto &[index, account] : _accounts) { - account->startMtp(); - } if (Local::oldSettingsVersion() < AppVersion) { Local::writeSettings(); } - - activate(active); + activateAfterStarting(); } else { Assert(!started()); } return result; } +void Accounts::accountAddedInStorage( + int index, + std::unique_ptr account) { + Expects(account != nullptr); + Expects(!_accounts.contains(index)); + + if (_accounts.empty()) { + _activeIndex = index; + } + _accounts.emplace(index, std::move(account)); +}; + +void Accounts::resetWithForgottenPasscode() { + if (_accounts.empty()) { + _local->startFromScratch(); + activateAfterStarting(); + } else { + for (const auto &[index, account] : _accounts) { + account->logOut(); + } + } +} + +void Accounts::activateAfterStarting() { + Expects(started()); + + for (const auto &[index, account] : _accounts) { + watchSession(account.get()); + } + + activate(_activeIndex); +} + const base::flat_map> &Accounts::list() const { return _accounts; } @@ -97,8 +114,6 @@ rpl::producer Accounts::activeSessionValue() const { } int Accounts::add() { - Expects(!Core::App().locked()); - auto index = 0; while (_accounts.contains(index)) { ++index; @@ -108,10 +123,57 @@ int Accounts::add() { std::make_unique(_dataName, index) ).first->second.get(); _local->startAdded(account); - account->startMtp(); + watchSession(account); return index; } +void Accounts::watchSession(not_null account) { + account->startMtp(); + account->sessionChanges( + ) | rpl::filter([=](Session *session) { + return !session && _accounts.size() > 1; + }) | rpl::start_with_next([=](Session *session) { + if (account == _active.current()) { + activateAuthedAccount(); + } + crl::on_main(&Core::App(), [=] { + removeRedundantAccounts(); + }); + }, account->lifetime()); +} + +void Accounts::activateAuthedAccount() { + Expects(started()); + + if (_active.current()->sessionExists()) { + return; + } + for (auto i = _accounts.begin(); i != _accounts.end(); ++i) { + if (i->second->sessionExists()) { + activate(i->first); + return; + } + } +} + +void Accounts::removeRedundantAccounts() { + Expects(started()); + + const auto was = _accounts.size(); + activateAuthedAccount(); + for (auto i = _accounts.begin(); i != _accounts.end();) { + if (i->second.get() == _active.current() + || i->second->sessionExists()) { + ++i; + continue; + } + i = _accounts.erase(i); + } + if (_accounts.size() != was) { + scheduleWriteAccounts(); + } +} + void Accounts::activate(int index) { Expects(_accounts.contains(index)); @@ -121,7 +183,16 @@ void Accounts::activate(int index) { _active.current()->sessionValue( ) | rpl::start_to_stream(_activeSessions, _activeLifetime); + scheduleWriteAccounts(); +} + +void Accounts::scheduleWriteAccounts() { + if (_writeAccountsScheduled) { + return; + } + _writeAccountsScheduled = true; crl::on_main(&Core::App(), [=] { + _writeAccountsScheduled = false; _local->writeAccounts(); }); } diff --git a/Telegram/SourceFiles/main/main_accounts.h b/Telegram/SourceFiles/main/main_accounts.h index e5039c97b..50b21f19a 100644 --- a/Telegram/SourceFiles/main/main_accounts.h +++ b/Telegram/SourceFiles/main/main_accounts.h @@ -23,7 +23,8 @@ public: ~Accounts(); [[nodiscard]] bool started() const; - Storage::StartResult start(const QByteArray &passcode); + [[nodiscard]] Storage::StartResult start(const QByteArray &passcode); + void resetWithForgottenPasscode(); [[nodiscard]] Storage::Accounts &local() const { return *_local; @@ -44,13 +45,23 @@ public: [[nodiscard]] int add(); void activate(int index); + // Interface for Storage::Accounts. + void accountAddedInStorage(int index, std::unique_ptr account); + private: + void activateAfterStarting(); + void activateAuthedAccount(); + void removeRedundantAccounts(); + void watchSession(not_null account); + void scheduleWriteAccounts(); + const QString _dataName; const std::unique_ptr _local; base::flat_map> _accounts; rpl::variable _active = nullptr; int _activeIndex = 0; + bool _writeAccountsScheduled = false; rpl::event_stream _activeSessions; diff --git a/Telegram/SourceFiles/main/main_session.cpp b/Telegram/SourceFiles/main/main_session.cpp index 7c6061c69..8b783124d 100644 --- a/Telegram/SourceFiles/main/main_session.cpp +++ b/Telegram/SourceFiles/main/main_session.cpp @@ -114,6 +114,7 @@ Session::Session( } Session::~Session() { + data().clear(); ClickHandler::clearActive(); ClickHandler::unpressed(); } diff --git a/Telegram/SourceFiles/mainwindow.cpp b/Telegram/SourceFiles/mainwindow.cpp index 6053f7ca1..13f93956f 100644 --- a/Telegram/SourceFiles/mainwindow.cpp +++ b/Telegram/SourceFiles/mainwindow.cpp @@ -652,22 +652,29 @@ void MainWindow::onShowNewChannel() { } } -void MainWindow::onLogout() { +void MainWindow::showLogoutConfirmation() { if (isHidden()) { showFromTray(); } - const auto callback = [=] { - if (account().sessionExists() - && account().session().data().exportInProgress()) { + const auto account = Core::App().passcodeLocked() + ? nullptr + : sessionController() + ? &sessionController()->session().account() + : nullptr; + const auto weak = base::make_weak(account); + const auto callback = crl::guard(weak, [=] { + if (account + && account->sessionExists() + && account->session().data().exportInProgress()) { Ui::hideLayer(); - account().session().data().stopExportWithConfirmation([=] { - account().logOut(); + account->session().data().stopExportWithConfirmation([=] { + Core::App().logout(account); }); } else { - account().logOut(); + Core::App().logout(account); } - }; + }); Ui::show(Box( tr::lng_sure_logout(tr::now), tr::lng_settings_logout(tr::now), diff --git a/Telegram/SourceFiles/mainwindow.h b/Telegram/SourceFiles/mainwindow.h index 831d1cc90..f0338935c 100644 --- a/Telegram/SourceFiles/mainwindow.h +++ b/Telegram/SourceFiles/mainwindow.h @@ -113,6 +113,8 @@ public: not_null photo); void hideMediaPreview(); + void showLogoutConfirmation(); + void updateControlsGeometry() override; protected: @@ -137,7 +139,6 @@ public slots: void onShowAddContact(); void onShowNewGroup(); void onShowNewChannel(); - void onLogout(); signals: void tempDirCleared(int task); diff --git a/Telegram/SourceFiles/platform/linux/main_window_linux.cpp b/Telegram/SourceFiles/platform/linux/main_window_linux.cpp index 91098f939..71f32f6be 100644 --- a/Telegram/SourceFiles/platform/linux/main_window_linux.cpp +++ b/Telegram/SourceFiles/platform/linux/main_window_linux.cpp @@ -756,10 +756,10 @@ void MainWindow::createGlobalMenu() { auto file = psMainMenu->addMenu(tr::lng_mac_menu_file(tr::now)); - psLogout = file->addAction( - tr::lng_mac_menu_logout(tr::now), - App::wnd(), - SLOT(onLogout())); + psLogout = file->addAction(tr::lng_mac_menu_logout(tr::now)); + connect(psLogout, &QAction::triggered, psLogout, [] { + if (App::wnd()) App::wnd()->showLogoutConfirmation(); + }); auto quit = file->addAction( tr::lng_mac_menu_quit_telegram(tr::now, lt_telegram, qsl("Telegram")), diff --git a/Telegram/SourceFiles/platform/mac/main_window_mac.mm b/Telegram/SourceFiles/platform/mac/main_window_mac.mm index 262e83680..f13059fde 100644 --- a/Telegram/SourceFiles/platform/mac/main_window_mac.mm +++ b/Telegram/SourceFiles/platform/mac/main_window_mac.mm @@ -681,7 +681,10 @@ void MainWindow::createGlobalMenu() { prefs->setMenuRole(QAction::PreferencesRole); QMenu *file = psMainMenu.addMenu(tr::lng_mac_menu_file(tr::now)); - psLogout = file->addAction(tr::lng_mac_menu_logout(tr::now), App::wnd(), SLOT(onLogout())); + psLogout = file->addAction(tr::lng_mac_menu_logout(tr::now)); + connect(psLogout, &QAction::triggered, psLogout, [] { + if (App::wnd()) App::wnd()->showLogoutConfirmation(); + }); QMenu *edit = psMainMenu.addMenu(tr::lng_mac_menu_edit(tr::now)); psUndo = edit->addAction(tr::lng_mac_menu_undo(tr::now), this, SLOT(psMacUndo()), QKeySequence::Undo); diff --git a/Telegram/SourceFiles/settings/settings_common.cpp b/Telegram/SourceFiles/settings/settings_common.cpp index 688ac1868..76b9f40bc 100644 --- a/Telegram/SourceFiles/settings/settings_common.cpp +++ b/Telegram/SourceFiles/settings/settings_common.cpp @@ -202,7 +202,7 @@ void FillMenu( } addAction( tr::lng_settings_logout(tr::now), - [=] { window->widget()->onLogout(); }); + [=] { window->widget()->showLogoutConfirmation(); }); } } diff --git a/Telegram/SourceFiles/storage/storage_accounts.cpp b/Telegram/SourceFiles/storage/storage_accounts.cpp index 8407fb589..a2daa9787 100644 --- a/Telegram/SourceFiles/storage/storage_accounts.cpp +++ b/Telegram/SourceFiles/storage/storage_accounts.cpp @@ -41,10 +41,8 @@ Accounts::Accounts(not_null owner, const QString &dataName) Accounts::~Accounts() = default; -StartResult Accounts::start( - const QByteArray &passcode, - Fn)> callback) { - const auto modern = startModern(passcode, callback); +StartResult Accounts::start(const QByteArray &passcode) { + const auto modern = startModern(passcode); if (modern == StartModernResult::Success) { if (_oldVersion < AppVersion) { writeAccounts(); @@ -53,20 +51,14 @@ StartResult Accounts::start( } else if (modern == StartModernResult::IncorrectPasscode) { return StartResult::IncorrectPasscode; } else if (modern == StartModernResult::Failed) { - startWithSingleAccount( - passcode, - std::move(callback), - std::make_unique(_dataName, 0)); + startFromScratch(); return StartResult::Success; } auto legacy = std::make_unique(_dataName, 0); const auto result = legacy->legacyStart(passcode); if (result == StartResult::Success) { _oldVersion = legacy->local().oldMapVersion(); - startWithSingleAccount( - passcode, - std::move(callback), - std::move(legacy)); + startWithSingleAccount(passcode, std::move(legacy)); } return result; } @@ -79,7 +71,6 @@ void Accounts::startAdded(not_null account) { void Accounts::startWithSingleAccount( const QByteArray &passcode, - Fn)> callback, std::unique_ptr account) { Expects(account != nullptr); @@ -90,7 +81,7 @@ void Accounts::startWithSingleAccount( generateLocalKey(); account->start(_localKey); } - callback(0, std::move(account)); + _owner->accountAddedInStorage(0, std::move(account)); writeAccounts(); } @@ -119,8 +110,7 @@ void Accounts::encryptLocalKey(const QByteArray &passcode) { } Accounts::StartModernResult Accounts::startModern( - const QByteArray &passcode, - Fn)> callback) { + const QByteArray &passcode) { const auto name = ComputeKeyName(_dataName); FileReadDescriptor keyData; @@ -185,7 +175,7 @@ Accounts::StartModernResult Accounts::startModern( const auto userId = account->willHaveUserId(); if (!users.contains(userId) && (userId != 0 || (users.empty() && i + 1 == count))) { - callback(index, std::move(account)); + _owner->accountAddedInStorage(index, std::move(account)); users.emplace(userId); } } @@ -223,6 +213,12 @@ void Accounts::writeAccounts() { key.writeEncrypted(keyData, _localKey); } +void Accounts::startFromScratch() { + startWithSingleAccount( + QByteArray(), + std::make_unique(_dataName, 0)); +} + bool Accounts::checkPasscode(const QByteArray &passcode) const { Expects(!_passcodeKeySalt.isEmpty()); Expects(_passcodeKey != nullptr); diff --git a/Telegram/SourceFiles/storage/storage_accounts.h b/Telegram/SourceFiles/storage/storage_accounts.h index 02d14d33c..3926bfd46 100644 --- a/Telegram/SourceFiles/storage/storage_accounts.h +++ b/Telegram/SourceFiles/storage/storage_accounts.h @@ -29,11 +29,10 @@ public: Accounts(not_null owner, const QString &dataName); ~Accounts(); - [[nodiscard]] StartResult start( - const QByteArray &passcode, - Fn)> callback); + [[nodiscard]] StartResult start(const QByteArray &passcode); void startAdded(not_null account); void writeAccounts(); + void startFromScratch(); [[nodiscard]] bool checkPasscode(const QByteArray &passcode) const; void setPasscode(const QByteArray &passcode); @@ -49,12 +48,9 @@ private: Empty, }; - [[nodiscard]] StartModernResult startModern( - const QByteArray &passcode, - Fn)> callback); + [[nodiscard]] StartModernResult startModern(const QByteArray &passcode); void startWithSingleAccount( const QByteArray &passcode, - Fn)> callback, std::unique_ptr account); void generateLocalKey(); void encryptLocalKey(const QByteArray &passcode); diff --git a/Telegram/SourceFiles/window/window_controller.cpp b/Telegram/SourceFiles/window/window_controller.cpp index b6fcc4c23..8b05d6983 100644 --- a/Telegram/SourceFiles/window/window_controller.cpp +++ b/Telegram/SourceFiles/window/window_controller.cpp @@ -68,7 +68,7 @@ void Controller::showAccount(not_null account) { } else { setupIntro(); } - }, _lifetime); + }, _accountLifetime); } void Controller::finishFirstShow() { diff --git a/Telegram/SourceFiles/window/window_lock_widgets.cpp b/Telegram/SourceFiles/window/window_lock_widgets.cpp index 08fd57f79..64953f444 100644 --- a/Telegram/SourceFiles/window/window_lock_widgets.cpp +++ b/Telegram/SourceFiles/window/window_lock_widgets.cpp @@ -117,7 +117,9 @@ PasscodeLockWidget::PasscodeLockWidget( connect(_passcode, &Ui::MaskedInputField::submitted, [=] { submit(); }); _submit->setClickedCallback([=] { submit(); }); - _logout->setClickedCallback([=] { window->widget()->onLogout(); }); + _logout->setClickedCallback([=] { + window->widget()->showLogoutConfirmation(); + }); } void PasscodeLockWidget::paintContent(Painter &p) {