From a2d4b9260e6f508a43a51775b60efc09cbc99d98 Mon Sep 17 00:00:00 2001
From: John Preston <johnprestonmail@gmail.com>
Date: Mon, 4 Jun 2018 21:18:52 +0300
Subject: [PATCH] Add AUTH_KEY_DROP_ service notification support.

Also move logout code to Messenger.
---
 Telegram/SourceFiles/app.cpp               | 37 -------------
 Telegram/SourceFiles/app.h                 |  2 -
 Telegram/SourceFiles/auth_session.cpp      |  2 +-
 Telegram/SourceFiles/boxes/confirm_box.cpp |  3 ++
 Telegram/SourceFiles/boxes/confirm_box.h   |  1 +
 Telegram/SourceFiles/facades.cpp           |  6 ---
 Telegram/SourceFiles/facades.h             |  2 -
 Telegram/SourceFiles/mainwidget.cpp        | 54 ++++++++++++++++---
 Telegram/SourceFiles/mainwindow.cpp        | 12 +++--
 Telegram/SourceFiles/messenger.cpp         | 63 +++++++++++++++++++---
 Telegram/SourceFiles/messenger.h           |  5 +-
 11 files changed, 120 insertions(+), 67 deletions(-)

diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp
index ffebdf65b..d8c11cf4b 100644
--- a/Telegram/SourceFiles/app.cpp
+++ b/Telegram/SourceFiles/app.cpp
@@ -147,43 +147,6 @@ namespace App {
 		return false;
 	}
 
-namespace {
-	bool loggedOut() {
-		if (Global::LocalPasscode()) {
-			Global::SetLocalPasscode(false);
-			Global::RefLocalPasscodeChanged().notify();
-		}
-		Media::Player::mixer()->stopAndClear();
-		if (auto w = wnd()) {
-			w->tempDirDelete(Local::ClearManagerAll);
-			w->setupIntro();
-		}
-		histories().clear();
-		Messenger::Instance().authSessionDestroy();
-		Local::reset();
-		Window::Theme::Background()->reset();
-
-		cSetOtherOnline(0);
-		clearStorageImages();
-		return true;
-	}
-} // namespace
-
-	void logOut() {
-		if (auto mtproto = Messenger::Instance().mtp()) {
-			mtproto->logout(rpcDone([] {
-				return loggedOut();
-			}), rpcFail([] {
-				return loggedOut();
-			}));
-		} else {
-			// We log out because we've forgotten passcode.
-			// So we just start mtproto from scratch.
-			Messenger::Instance().startMtp();
-			loggedOut();
-		}
-	}
-
 	namespace {
 		// we should get a full restriction in "{fulltype}: {reason}" format and we
 		// need to find a "-all" tag in {fulltype}, otherwise ignore this restriction
diff --git a/Telegram/SourceFiles/app.h b/Telegram/SourceFiles/app.h
index 3680a2f4d..021a3e582 100644
--- a/Telegram/SourceFiles/app.h
+++ b/Telegram/SourceFiles/app.h
@@ -68,8 +68,6 @@ namespace App {
 	MainWidget *main();
 	bool passcoded();
 
-	void logOut();
-
 	QString formatPhone(QString phone);
 
 	UserData *feedUser(const MTPUser &user);
diff --git a/Telegram/SourceFiles/auth_session.cpp b/Telegram/SourceFiles/auth_session.cpp
index 6c580cb5b..8ce8b33c1 100644
--- a/Telegram/SourceFiles/auth_session.cpp
+++ b/Telegram/SourceFiles/auth_session.cpp
@@ -314,7 +314,7 @@ bool AuthSession::validateSelf(const MTPUser &user) {
 		return false;
 	} else if (user.c_user().vid.v != userId()) {
 		LOG(("Auth Error: wrong self user received."));
-		App::logOutDelayed();
+		crl::on_main(this, [] { Messenger::Instance().logOut(); });
 		return false;
 	}
 	return true;
diff --git a/Telegram/SourceFiles/boxes/confirm_box.cpp b/Telegram/SourceFiles/boxes/confirm_box.cpp
index 93175cdfc..1b89807b1 100644
--- a/Telegram/SourceFiles/boxes/confirm_box.cpp
+++ b/Telegram/SourceFiles/boxes/confirm_box.cpp
@@ -250,6 +250,9 @@ InformBox::InformBox(QWidget*, const QString &text, const QString &doneText, Fn<
 InformBox::InformBox(QWidget*, const TextWithEntities &text, Fn<void()> closedCallback) : ConfirmBox(ConfirmBox::InformBoxTag(), text, lang(lng_box_ok), std::move(closedCallback)) {
 }
 
+InformBox::InformBox(QWidget*, const TextWithEntities &text, const QString &doneText, Fn<void()> closedCallback) : ConfirmBox(ConfirmBox::InformBoxTag(), text, doneText, std::move(closedCallback)) {
+}
+
 MaxInviteBox::MaxInviteBox(QWidget*, not_null<ChannelData*> channel) : BoxContent()
 , _channel(channel)
 , _text(st::boxLabelStyle, lng_participant_invite_sorry(lt_count, Global::ChatSizeMax()), _confirmBoxTextOptions, st::boxWidth - st::boxPadding.left() - st::boxButtonPadding.right()) {
diff --git a/Telegram/SourceFiles/boxes/confirm_box.h b/Telegram/SourceFiles/boxes/confirm_box.h
index 9c2ee6caa..c0c0d0009 100644
--- a/Telegram/SourceFiles/boxes/confirm_box.h
+++ b/Telegram/SourceFiles/boxes/confirm_box.h
@@ -87,6 +87,7 @@ public:
 	InformBox(QWidget*, const QString &text, Fn<void()> closedCallback = nullptr);
 	InformBox(QWidget*, const QString &text, const QString &doneText, Fn<void()> closedCallback = nullptr);
 	InformBox(QWidget*, const TextWithEntities &text, Fn<void()> closedCallback = nullptr);
+	InformBox(QWidget*, const TextWithEntities &text, const QString &doneText, Fn<void()> closedCallback = nullptr);
 
 };
 
diff --git a/Telegram/SourceFiles/facades.cpp b/Telegram/SourceFiles/facades.cpp
index 7deb2a4d4..a851c9657 100644
--- a/Telegram/SourceFiles/facades.cpp
+++ b/Telegram/SourceFiles/facades.cpp
@@ -183,12 +183,6 @@ void activateClickHandler(ClickHandlerPtr handler, Qt::MouseButton button) {
 	});
 }
 
-void logOutDelayed() {
-	InvokeQueued(QCoreApplication::instance(), [] {
-		App::logOut();
-	});
-}
-
 } // namespace App
 
 namespace Ui {
diff --git a/Telegram/SourceFiles/facades.h b/Telegram/SourceFiles/facades.h
index 8e90cffa1..5b4a75db7 100644
--- a/Telegram/SourceFiles/facades.h
+++ b/Telegram/SourceFiles/facades.h
@@ -76,8 +76,6 @@ void showSettings();
 
 void activateClickHandler(ClickHandlerPtr handler, Qt::MouseButton button);
 
-void logOutDelayed();
-
 } // namespace App
 
 
diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp
index a9940bdd5..1db6ae7fe 100644
--- a/Telegram/SourceFiles/mainwidget.cpp
+++ b/Telegram/SourceFiles/mainwidget.cpp
@@ -87,6 +87,41 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "styles/style_history.h"
 #include "styles/style_boxes.h"
 
+namespace {
+
+bool IsForceLogoutNotification(const MTPDupdateServiceNotification &data) {
+	return qs(data.vtype).startsWith(qstr("AUTH_KEY_DROP_"));
+}
+
+bool HasForceLogoutNotification(const MTPUpdates &updates) {
+	const auto checkUpdate = [](const MTPUpdate &update) {
+		if (update.type() != mtpc_updateServiceNotification) {
+			return false;
+		}
+		return IsForceLogoutNotification(
+			update.c_updateServiceNotification());
+	};
+	const auto checkVector = [&](const MTPVector<MTPUpdate> &list) {
+		for (const auto &update : list.v) {
+			if (checkUpdate(update)) {
+				return true;
+			}
+		}
+		return false;
+	};
+	switch (updates.type()) {
+	case mtpc_updates:
+		return checkVector(updates.c_updates().vupdates);
+	case mtpc_updatesCombined:
+		return checkVector(updates.c_updatesCombined().vupdates);
+	case mtpc_updateShort:
+		return checkUpdate(updates.c_updateShort().vupdate);
+	}
+	return false;
+}
+
+} // namespace
+
 enum StackItemType {
 	HistoryStackItem,
 	SectionStackItem,
@@ -3293,7 +3328,7 @@ void MainWidget::feedMessageIds(const MTPVector<MTPUpdate> &updates) {
 }
 
 bool MainWidget::updateFail(const RPCError &e) {
-	App::logOutDelayed();
+	crl::on_main(this, [] { Messenger::Instance().logOut(); });
 	return true;
 }
 
@@ -4231,7 +4266,8 @@ void MainWidget::updateReceived(const mtpPrime *from, const mtpPrime *end) {
 
 			_lastUpdateTime = getms(true);
 			noUpdatesTimer.start(NoUpdatesTimeout);
-			if (!requestingDifference()) {
+			if (!requestingDifference()
+				|| HasForceLogoutNotification(updates)) {
 				feedUpdates(updates);
 			}
 		} catch (mtpErrorUnexpected &) { // just some other type
@@ -4899,11 +4935,17 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
 	} break;
 
 	case mtpc_updateServiceNotification: {
-		auto &d = update.c_updateServiceNotification();
-		if (d.is_popup()) {
-			Ui::show(Box<InformBox>(qs(d.vmessage)));
+		const auto &d = update.c_updateServiceNotification();
+		const auto text = TextWithEntities {
+			qs(d.vmessage),
+			TextUtilities::EntitiesFromMTP(d.ventities.v)
+		};
+		if (IsForceLogoutNotification(d)) {
+			Messenger::Instance().forceLogOut(text);
+		} else if (d.is_popup()) {
+			Ui::show(Box<InformBox>(text));
 		} else {
-			App::wnd()->serviceNotification({ qs(d.vmessage), TextUtilities::EntitiesFromMTP(d.ventities.v) }, d.vmedia);
+			App::wnd()->serviceNotification(text, d.vmedia);
 			emit App::wnd()->checkNewAuthorization();
 		}
 	} break;
diff --git a/Telegram/SourceFiles/mainwindow.cpp b/Telegram/SourceFiles/mainwindow.cpp
index 3b8fde933..da4c98341 100644
--- a/Telegram/SourceFiles/mainwindow.cpp
+++ b/Telegram/SourceFiles/mainwindow.cpp
@@ -606,11 +606,15 @@ void MainWindow::onShowNewChannel() {
 }
 
 void MainWindow::onLogout() {
-	if (isHidden()) showFromTray();
+	if (isHidden()) {
+		showFromTray();
+	}
 
-	Ui::show(Box<ConfirmBox>(lang(lng_sure_logout), lang(lng_settings_logout), st::attentionBoxButton, [] {
-		App::logOut();
-	}));
+	Ui::show(Box<ConfirmBox>(
+		lang(lng_sure_logout),
+		lang(lng_settings_logout),
+		st::attentionBoxButton,
+		[] { Messenger::Instance().logOut(); }));
 }
 
 void MainWindow::quitFromTray() {
diff --git a/Telegram/SourceFiles/messenger.cpp b/Telegram/SourceFiles/messenger.cpp
index 686514b70..6a2eb3367 100644
--- a/Telegram/SourceFiles/messenger.cpp
+++ b/Telegram/SourceFiles/messenger.cpp
@@ -35,6 +35,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "mtproto/dc_options.h"
 #include "mtproto/mtp_instance.h"
 #include "media/player/media_player_instance.h"
+#include "media/media_audio.h"
 #include "media/media_audio_track.h"
 #include "window/notifications_manager.h"
 #include "window/themes/window_theme.h"
@@ -508,20 +509,24 @@ void Messenger::suggestMainDcId(MTP::DcId mainDcId) {
 void Messenger::destroyStaleAuthorizationKeys() {
 	Assert(_mtproto != nullptr);
 
-	auto keys = _mtproto->getKeysForWrite();
-	for (auto &key : keys) {
+	for (const auto &key : _mtproto->getKeysForWrite()) {
 		// Disable this for now.
 		if (key->type() == MTP::AuthKey::Type::ReadFromFile) {
 			_private->mtpKeysToDestroy = _mtproto->getKeysForWrite();
-			_mtproto.reset();
-			LOG(("MTP Info: destroying stale keys, count: %1").arg(_private->mtpKeysToDestroy.size()));
-			startMtp();
-			Local::writeMtpData();
+			LOG(("MTP Info: destroying stale keys, count: %1"
+				).arg(_private->mtpKeysToDestroy.size()));
+			resetAuthorizationKeys();
 			return;
 		}
 	}
 }
 
+void Messenger::resetAuthorizationKeys() {
+	_mtproto.reset();
+	startMtp();
+	Local::writeMtpData();
+}
+
 void Messenger::startLocalStorage() {
 	_dcOptions = std::make_unique<MTP::DcOptions>();
 	_dcOptions->constructFromBuiltIn();
@@ -650,6 +655,18 @@ void Messenger::killDownloadSessionsStop(MTP::DcId dcId) {
 	}
 }
 
+void Messenger::forceLogOut(const TextWithEntities &explanation) {
+	const auto box = Ui::show(Box<InformBox>(
+		explanation,
+		lang(lng_passcode_logout)));
+	connect(box, &QObject::destroyed, [=] {
+		InvokeQueued(this, [=] {
+			resetAuthorizationKeys();
+			loggedOut();
+		});
+	});
+}
+
 void Messenger::checkLocalTime() {
 	if (App::main()) App::main()->checkLastUpdate(checkms());
 }
@@ -777,8 +794,6 @@ void Messenger::authSessionDestroy() {
 	_private->storedAuthSession.reset();
 	_private->authSessionUserId = 0;
 	authSessionChanged().notify(true);
-
-	loggedOut();
 }
 
 void Messenger::setInternalLinkDomain(const QString &domain) const {
@@ -1097,11 +1112,43 @@ void Messenger::checkMediaViewActivation() {
 	}
 }
 
+void Messenger::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 Messenger::loggedOut() {
+	if (Global::LocalPasscode()) {
+		Global::SetLocalPasscode(false);
+		Global::RefLocalPasscodeChanged().notify();
+	}
+	Media::Player::mixer()->stopAndClear();
+	if (const auto w = getActiveWindow()) {
+		w->tempDirDelete(Local::ClearManagerAll);
+		w->setupIntro();
+	}
+	App::histories().clear();
+	authSessionDestroy();
 	if (_mediaView) {
 		hideMediaView();
 		_mediaView->clearData();
 	}
+	Local::reset();
+	Window::Theme::Background()->reset();
+
+	cSetOtherOnline(0);
+	clearStorageImages();
 }
 
 QPoint Messenger::getPointForCallPanelCenter() const {
diff --git a/Telegram/SourceFiles/messenger.h b/Telegram/SourceFiles/messenger.h
index 895ae8a81..101569f68 100644
--- a/Telegram/SourceFiles/messenger.h
+++ b/Telegram/SourceFiles/messenger.h
@@ -132,10 +132,10 @@ public:
 		return _langCloudManager.get();
 	}
 	void authSessionCreate(UserId userId);
-	void authSessionDestroy();
 	base::Observable<void> &authSessionChanged() {
 		return _authSessionChanged;
 	}
+	void logOut();
 
 	// Media component.
 	Media::Audio::Instance &audio() {
@@ -166,6 +166,7 @@ public:
 	void killDownloadSessionsStart(MTP::DcId dcId);
 	void killDownloadSessionsStop(MTP::DcId dcId);
 
+	void forceLogOut(const TextWithEntities &explanation);
 	void checkLocalTime();
 	void setupPasscode();
 	void clearPasscode();
@@ -215,6 +216,8 @@ private:
 	void quitDelayed();
 
 	void photoUpdated(const FullMsgId &msgId, const MTPInputFile &file);
+	void resetAuthorizationKeys();
+	void authSessionDestroy();
 	void loggedOut();
 
 	not_null<Core::Launcher*> _launcher;