diff --git a/cockatrice/CMakeLists.txt b/cockatrice/CMakeLists.txt index 12733afe6..3ade2a8c9 100644 --- a/cockatrice/CMakeLists.txt +++ b/cockatrice/CMakeLists.txt @@ -7,6 +7,7 @@ project(Cockatrice VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${ set(cockatrice_SOURCES ${VERSION_STRING_CPP} # sort by alphabetical order, so that there is no debate about where to add new sources to the list + src/client/network/connection_controller/remote_connection_controller.cpp src/client/network/update/client/update_downloader.cpp src/client/network/interfaces/deck_stats_interface.cpp src/client/network/interfaces/tapped_out_interface.cpp diff --git a/cockatrice/src/client/network/connection_controller/remote_connection_controller.cpp b/cockatrice/src/client/network/connection_controller/remote_connection_controller.cpp new file mode 100644 index 000000000..f517acdc4 --- /dev/null +++ b/cockatrice/src/client/network/connection_controller/remote_connection_controller.cpp @@ -0,0 +1,581 @@ +#include "remote_connection_controller.h" + +#include "../../settings/cache_settings.h" +#include "../interface/widgets/dialogs/dlg_connect.h" +#include "../interface/widgets/dialogs/dlg_forgot_password_challenge.h" +#include "../interface/widgets/dialogs/dlg_forgot_password_request.h" +#include "../interface/widgets/dialogs/dlg_forgot_password_reset.h" +#include "../interface/widgets/dialogs/dlg_register.h" +#include "../interface/widgets/utility/get_text_with_max.h" + +#include +#include +#include +#include +#include +#include + +ConnectionController::ConnectionController(QWidget *dialogParent, QObject *parent) + : QObject(parent), dialogParent(dialogParent) +{ + remoteClient = new RemoteClient(nullptr, &SettingsCache::instance()); + + clientThread = new QThread(this); + remoteClient->moveToThread(clientThread); + clientThread->start(); + + wireClientSignals(); +} + +ConnectionController::~ConnectionController() +{ + remoteClient->deleteLater(); + clientThread->wait(); +} + +void ConnectionController::wireClientSignals() +{ + connect(remoteClient, &RemoteClient::connectionClosedEventReceived, this, + &ConnectionController::onConnectionClosedEvent); + + connect(remoteClient, &RemoteClient::serverShutdownEventReceived, this, + &ConnectionController::onServerShutdownEvent); + + connect(remoteClient, &RemoteClient::statusChanged, this, &ConnectionController::onStatusChanged); + + connect(remoteClient, &RemoteClient::userInfoChanged, this, &ConnectionController::onUserInfoReceived, + Qt::BlockingQueuedConnection); + + connect(remoteClient, &RemoteClient::loginError, this, + [this](Response::ResponseCode r, QString rs, quint32 et, QList mf) { + onLoginError(static_cast(r), rs, et, mf); + }); + + connect(remoteClient, &RemoteClient::registerError, this, + [this](Response::ResponseCode r, QString rs, quint32 et) { onRegisterError(static_cast(r), rs, et); }); + + connect(remoteClient, &RemoteClient::activateError, this, &ConnectionController::onActivateError); + connect(remoteClient, &RemoteClient::socketError, this, &ConnectionController::onSocketError); + connect(remoteClient, &RemoteClient::serverTimeout, this, &ConnectionController::onServerTimeout); + + connect(remoteClient, &RemoteClient::protocolVersionMismatch, this, + &ConnectionController::onProtocolVersionMismatch); + + connect(remoteClient, &RemoteClient::registerAccepted, this, &ConnectionController::onRegisterAccepted); + + connect(remoteClient, &RemoteClient::registerAcceptedNeedsActivate, this, + &ConnectionController::onRegisterAcceptedNeedsActivate); + + connect(remoteClient, &RemoteClient::activateAccepted, this, &ConnectionController::onActivateAccepted); + + connect(remoteClient, &RemoteClient::notifyUserAboutUpdate, this, &ConnectionController::onNotifyUserAboutUpdate); + + connect(remoteClient, &RemoteClient::sigForgotPasswordSuccess, this, + &ConnectionController::onForgotPasswordSuccess); + + connect(remoteClient, &RemoteClient::sigForgotPasswordError, this, &ConnectionController::onForgotPasswordError); + + connect(remoteClient, &RemoteClient::sigPromptForForgotPasswordReset, this, + &ConnectionController::onPromptForgotPasswordReset); + + connect(remoteClient, &RemoteClient::sigPromptForForgotPasswordChallenge, this, + &ConnectionController::onPromptForgotPasswordChallenge); +} + +void ConnectionController::connectToServer() +{ + dlgConnect = new DlgConnect(dialogParent); + connect(dlgConnect, &DlgConnect::sigStartForgotPasswordRequest, this, &ConnectionController::forgotPasswordRequest); + + if (dlgConnect->exec()) { + remoteClient->connectToServer(dlgConnect->getHost(), static_cast(dlgConnect->getPort()), + dlgConnect->getPlayerName(), dlgConnect->getPassword()); + } +} + +void ConnectionController::connectToServerDirect(const QString &host, + unsigned int port, + const QString &playerName, + const QString &password) +{ + remoteClient->connectToServer(host, port, playerName, password); +} + +void ConnectionController::disconnectFromServer() +{ + remoteClient->disconnectFromServer(); +} + +void ConnectionController::registerToServer() +{ + DlgRegister dlg(dialogParent); + if (dlg.exec()) { + remoteClient->registerToServer(dlg.getHost(), static_cast(dlg.getPort()), dlg.getPlayerName(), + dlg.getPassword(), dlg.getEmail(), dlg.getCountry(), dlg.getRealName()); + } +} + +void ConnectionController::forgotPasswordRequest() +{ + DlgForgotPasswordRequest dlg(dialogParent); + if (dlg.exec()) { + remoteClient->requestForgotPasswordToServer(dlg.getHost(), static_cast(dlg.getPort()), + dlg.getPlayerName()); + } +} + +void ConnectionController::onConnectionClosedEvent(const Event_ConnectionClosed &event) +{ + remoteClient->disconnectFromServer(); + + QString reasonStr; + switch (event.reason()) { + case Event_ConnectionClosed::USER_LIMIT_REACHED: { + reasonStr = tr("The server has reached its maximum user capacity, please check back later."); + break; + } + case Event_ConnectionClosed::TOO_MANY_CONNECTIONS: { + reasonStr = tr("There are too many concurrent connections from your address."); + break; + } + case Event_ConnectionClosed::BANNED: { + reasonStr = tr("Banned by moderator"); + if (event.has_end_time()) + reasonStr.append( + "\n" + tr("Expected end time: %1").arg(QDateTime::fromSecsSinceEpoch(event.end_time()).toString())); + else + reasonStr.append("\n" + tr("This ban lasts indefinitely.")); + if (event.has_reason_str()) + reasonStr.append("\n\n" + QString::fromStdString(event.reason_str())); + break; + } + case Event_ConnectionClosed::SERVER_SHUTDOWN: { + reasonStr = tr("Scheduled server shutdown."); + break; + } + case Event_ConnectionClosed::USERNAMEINVALID: { + reasonStr = tr("Invalid username."); + break; + } + case Event_ConnectionClosed::LOGGEDINELSEWERE: { + reasonStr = tr("You have been logged out due to logging in at another location."); + break; + } + default: + reasonStr = QString::fromStdString(event.reason_str()); + } + + QMessageBox::critical(dialogParent, tr("Connection closed"), + tr("The server has terminated your connection.\nReason: %1").arg(reasonStr)); +} + +void ConnectionController::onServerShutdownEvent(const Event_ServerShutdown &event) +{ + serverShutdownMessageBox.setInformativeText(tr("The server is going to be restarted in %n minute(s).\nAll running " + "games will be lost.\nReason for shutdown: %1", + "", event.minutes()) + .arg(QString::fromStdString(event.reason()))); + serverShutdownMessageBox.setIconPixmap(QPixmap("theme:cockatrice").scaled(64, 64)); + serverShutdownMessageBox.setText(tr("Scheduled server shutdown")); + serverShutdownMessageBox.setWindowModality(Qt::ApplicationModal); + serverShutdownMessageBox.setVisible(true); +} + +void ConnectionController::onStatusChanged(ClientStatus status) +{ + // Update the window title first, then let MainWindow handle its own UI + // state via the forwarded signal + updateWindowTitle(); + emit statusChanged(status); + + // TabSupervisor::stop() needs calling on disconnect; start() is driven by + // onUserInfoReceived → tabSupervisorStartRequested. + if (status == StatusDisconnected) { + emit tabSupervisorStopRequested(); + } +} + +void ConnectionController::onUserInfoReceived(const ServerInfo_User &info) +{ + emit tabSupervisorStartRequested(info); +} + +void ConnectionController::onLoginError(int r, + QString reasonStr, + quint32 endTime, + const QList &missingFeatures) +{ + switch (static_cast(r)) { + case Response::RespClientUpdateRequired: { + QString formatted = "Missing Features: "; + for (int i = 0; i < missingFeatures.size(); ++i) { + formatted.append(QString("\n %1").arg(QChar(0x2022)) + " " + missingFeatures.value(i)); + } + + QMessageBox msgBox(dialogParent); + msgBox.setIcon(QMessageBox::Critical); + msgBox.setWindowTitle(tr("Failed Login")); + msgBox.setText(tr("Your client seems to be missing features this server requires for connection.") + + "\n\n" + tr("To update your client, go to 'Help -> Check for Client Updates'.")); + msgBox.setDetailedText(formatted); + msgBox.exec(); + break; + } + + case Response::RespWrongPassword: { + QMessageBox::critical(dialogParent, tr("Error"), + tr("Incorrect username or password. " + "Please check your authentication information and try again.")); + break; + } + + case Response::RespWouldOverwriteOldSession: { + QMessageBox::critical(dialogParent, tr("Error"), + tr("There is already an active session using this user name.\n" + "Please close that session first and re-login.")); + break; + } + + case Response::RespUserIsBanned: { + QString bannedStr = + endTime ? tr("You are banned until %1.").arg(QDateTime::fromSecsSinceEpoch(endTime).toString()) + : tr("You are banned indefinitely."); + if (!reasonStr.isEmpty()) + bannedStr.append("\n\n" + reasonStr); + QMessageBox::critical(dialogParent, tr("Error"), bannedStr); + break; + } + + case Response::RespUsernameInvalid: { + QMessageBox::critical(dialogParent, tr("Error"), extractInvalidUsernameMessage(reasonStr)); + break; + } + + case Response::RespRegistrationRequired: { + if (QMessageBox::question(dialogParent, tr("Error"), + tr("This server requires user registration. Do you want to register now?"), + QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { + registerToServer(); + } + return; // don't re-prompt connect + } + + case Response::RespClientIdRequired: { + QMessageBox::critical(dialogParent, tr("Error"), + tr("This server requires client IDs. Your client is either failing to generate an " + "ID or you are running a modified client.\n" + "Please close and reopen your client to try again.")); + break; + } + + case Response::RespContextError: { + QMessageBox::critical(dialogParent, tr("Error"), + tr("An internal error has occurred, please close and reopen Cockatrice before " + "trying again.\nIf the error persists, ensure you are running the latest " + "version of the software and if needed contact the software developers.")); + break; + } + + case Response::RespAccountNotActivated: { + bool ok = false; + QString token = + getTextWithMax(dialogParent, tr("Account activation"), + tr("Your account has not been activated yet.\n" + "You need to provide the activation token received in the activation email."), + QLineEdit::Normal, QString(), &ok); + + if (ok && !token.isEmpty()) { + remoteClient->activateToServer(token); + return; + } + remoteClient->disconnectFromServer(); + return; + } + + case Response::RespServerFull: { + QMessageBox::critical(dialogParent, tr("Server Full"), + tr("The server has reached its maximum user capacity, please check back later.")); + break; + } + + default: { + QMessageBox::critical(dialogParent, tr("Error"), + tr("Unknown login error: %1").arg(r) + + tr("\nThis usually means that your client version is out of date, and the server " + "sent a reply your client doesn't understand.")); + break; + } + } + + // Re-open the connect dialog after any handled error + connectToServer(); +} + +void ConnectionController::onRegisterError(int r, QString reasonStr, quint32 endTime) +{ + switch (static_cast(r)) { + case Response::RespRegistrationDisabled: { + QMessageBox::critical(dialogParent, tr("Registration denied"), + tr("Registration is currently disabled on this server")); + break; + } + case Response::RespUserAlreadyExists: { + QMessageBox::critical(dialogParent, tr("Registration denied"), + tr("There is already an existing account with the same user name.")); + break; + } + case Response::RespEmailRequiredToRegister: { + QMessageBox::critical(dialogParent, tr("Registration denied"), + tr("It's mandatory to specify a valid email address when registering.")); + break; + } + case Response::RespEmailBlackListed: { + if (reasonStr.isEmpty()) { + reasonStr = + "The email address provider used during registration has been blocked from use on this server."; + } + QMessageBox::critical(dialogParent, tr("Registration denied"), reasonStr); + break; + } + case Response::RespTooManyRequests: { + QMessageBox::critical(dialogParent, tr("Registration denied"), + tr("It appears you are attempting to register a new account on this server yet you " + "already have an account registered with the email provided. This server " + "restricts the number of accounts a user can register per address. Please " + "contact the server operator for further assistance or to obtain your " + "credential information.")); + break; + } + case Response::RespPasswordTooShort: { + QMessageBox::critical(dialogParent, tr("Registration denied"), tr("Password too short.")); + break; + } + case Response::RespUserIsBanned: { + QString bannedStr = + endTime ? tr("You are banned until %1.").arg(QDateTime::fromSecsSinceEpoch(endTime).toString()) + : tr("You are banned indefinitely."); + if (!reasonStr.isEmpty()) + bannedStr.append("\n\n" + reasonStr); + QMessageBox::critical(dialogParent, tr("Error"), bannedStr); + break; + } + case Response::RespUsernameInvalid: { + QMessageBox::critical(dialogParent, tr("Error"), extractInvalidUsernameMessage(reasonStr)); + break; + } + case Response::RespRegistrationFailed: { + QMessageBox::critical(dialogParent, tr("Error"), + tr("Registration failed for a technical problem on the server.")); + break; + } + case Response::RespNotConnected: { + QMessageBox::critical(dialogParent, tr("Error"), tr("The connection to the server has been lost.")); + break; + } + default: { + QMessageBox::critical(dialogParent, tr("Error"), + tr("Unknown registration error: %1").arg(r) + + tr("\nThis usually means that your client version is out of date, and the server " + "sent a reply your client doesn't understand.")); + break; + } + } + + registerToServer(); +} + +void ConnectionController::onActivateError() +{ + QMessageBox::critical(dialogParent, tr("Error"), tr("Account activation failed")); + remoteClient->disconnectFromServer(); + connectToServer(); +} + +void ConnectionController::onSocketError(const QString &errorStr) +{ + QMessageBox::critical(dialogParent, tr("Error"), tr("Socket error: %1").arg(errorStr)); + connectToServer(); +} + +void ConnectionController::onServerTimeout() +{ + QMessageBox::critical(dialogParent, tr("Error"), tr("Server timeout")); + connectToServer(); +} + +void ConnectionController::onProtocolVersionMismatch(int localVersion, int remoteVersion) +{ + if (localVersion > remoteVersion) { + QMessageBox::critical(dialogParent, tr("Error"), + tr("You are trying to connect to an obsolete server. Please downgrade your Cockatrice " + "version or connect to a suitable server.\n" + "Local version is %1, remote version is %2.") + .arg(localVersion) + .arg(remoteVersion)); + } else { + QMessageBox::critical(dialogParent, tr("Error"), + tr("Your Cockatrice client is obsolete. Please update your Cockatrice version.\n" + "Local version is %1, remote version is %2.") + .arg(localVersion) + .arg(remoteVersion)); + } +} + +void ConnectionController::onRegisterAccepted() +{ + QMessageBox::information(dialogParent, tr("Success"), tr("Registration accepted.\nWill now login.")); +} + +void ConnectionController::onRegisterAcceptedNeedsActivate() +{ + // Server will send activation email; nothing to display here. +} + +void ConnectionController::onActivateAccepted() +{ + QMessageBox::information(dialogParent, tr("Success"), tr("Account activation accepted.\nWill now login.")); +} + +void ConnectionController::onNotifyUserAboutUpdate() +{ + QMessageBox::information( + dialogParent, tr("Information"), + tr("This server supports additional features that your client doesn't have.\n" + "This is most likely not a problem, but this message might mean there is a new version of " + "Cockatrice available or this server is running a custom or pre-release version.\n\n" + "To update your client, go to Help -> Check for Updates.")); +} + +void ConnectionController::onForgotPasswordSuccess() +{ + QMessageBox::information( + dialogParent, tr("Reset Password"), + tr("Your password has been reset successfully, you can now log in using the new credentials.")); + SettingsCache::instance().servers().setFPHostName(""); + SettingsCache::instance().servers().setFPPort(""); + SettingsCache::instance().servers().setFPPlayerName(""); +} + +void ConnectionController::onForgotPasswordError() +{ + QMessageBox::warning( + dialogParent, tr("Reset Password"), + tr("Failed to reset user account password, please contact the server operator to reset your password.")); + SettingsCache::instance().servers().setFPHostName(""); + SettingsCache::instance().servers().setFPPort(""); + SettingsCache::instance().servers().setFPPlayerName(""); +} + +void ConnectionController::onPromptForgotPasswordReset() +{ + QMessageBox::information(dialogParent, tr("Reset Password"), + tr("Activation request received, please check your email for an activation token.")); + DlgForgotPasswordReset dlg(dialogParent); + if (dlg.exec()) { + remoteClient->submitForgotPasswordResetToServer(dlg.getHost(), static_cast(dlg.getPort()), + dlg.getPlayerName(), dlg.getToken(), dlg.getPassword()); + } +} + +void ConnectionController::onPromptForgotPasswordChallenge() +{ + DlgForgotPasswordChallenge dlg(dialogParent); + if (dlg.exec()) { + remoteClient->submitForgotPasswordChallengeToServer(dlg.getHost(), static_cast(dlg.getPort()), + dlg.getPlayerName(), dlg.getEmail()); + } +} + +void ConnectionController::updateWindowTitle() +{ + const QString appName = QStringLiteral("Cockatrice"); + QString title; + + switch (remoteClient->getStatus()) { + case StatusConnecting: { + title = appName + " - " + tr("Connecting to %1...").arg(remoteClient->peerName()); + break; + } + case StatusRegistering: { + title = appName + " - " + + tr("Registering to %1 as %2...").arg(remoteClient->peerName()).arg(remoteClient->getUserName()); + break; + } + case StatusDisconnected: { + title = appName + " - " + tr("Disconnected"); + break; + } + case StatusLoggingIn: { + title = appName + " - " + tr("Connected, logging in at %1").arg(remoteClient->peerName()); + break; + } + case StatusLoggedIn: { + title = remoteClient->getUserName() + "@" + remoteClient->peerName(); + break; + } + case StatusRequestingForgotPassword: + case StatusSubmitForgotPasswordChallenge: + case StatusSubmitForgotPasswordReset: + title = appName + " - " + + tr("Requesting forgotten password to %1 as %2...") + .arg(remoteClient->peerName()) + .arg(remoteClient->getUserName()); + break; + default: + title = appName; + } + + emit windowTitleChanged(title); +} + +// static +QString ConnectionController::extractInvalidUsernameMessage(QString &in) +{ + QString out = tr("Invalid username.") + "
"; + QStringList rules = in.split(QChar('|')); + + if (rules.size() == 7 || rules.size() == 9) { + out += tr("Your username must respect these rules:") + "
    "; + + out += "
  • " + tr("is %1 - %2 characters long").arg(rules.at(0)).arg(rules.at(1)) + "
  • "; + out += "
  • " + tr("can %1 contain lowercase characters").arg((rules.at(2).toInt() > 0) ? "" : tr("NOT")) + + "
  • "; + out += "
  • " + tr("can %1 contain uppercase characters").arg((rules.at(3).toInt() > 0) ? "" : tr("NOT")) + + "
  • "; + out += + "
  • " + tr("can %1 contain numeric characters").arg((rules.at(4).toInt() > 0) ? "" : tr("NOT")) + "
  • "; + + if (rules.at(6).size() > 0) + out += "
  • " + tr("can contain the following punctuation: %1").arg(rules.at(6).toHtmlEscaped()) + "
  • "; + + out += "
  • " + + tr("first character can %1 be a punctuation mark").arg((rules.at(5).toInt() > 0) ? "" : tr("NOT")) + + "
  • "; + + if (rules.size() == 9) { + if (rules.at(7).size() > 0) { + QString words = rules.at(7).toHtmlEscaped(); + if (words.startsWith("\n")) { + out += tr("no unacceptable language as specified by these server rules:", + "note that the following lines will not be translated"); + for (QString &line : words.split("\n", Qt::SkipEmptyParts)) { + out += "
  • " + line + "
  • "; + } + } else { + out += "
  • " + tr("can not contain any of the following words: %1").arg(words) + "
  • "; + } + } + + if (rules.at(8).size() > 0) + out += "
  • " + + tr("can not match any of the following expressions: %1").arg(rules.at(8).toHtmlEscaped()) + + "
  • "; + } + + out += "
"; + } else { + out += tr("You may only use A-Z, a-z, 0-9, _, ., and - in your username."); + } + + return out; +} \ No newline at end of file diff --git a/cockatrice/src/client/network/connection_controller/remote_connection_controller.h b/cockatrice/src/client/network/connection_controller/remote_connection_controller.h new file mode 100644 index 000000000..7486bc81a --- /dev/null +++ b/cockatrice/src/client/network/connection_controller/remote_connection_controller.h @@ -0,0 +1,98 @@ +#ifndef COCKATRICE_REMOTE_CONNECTION_CONTROLLER_H +#define COCKATRICE_REMOTE_CONNECTION_CONTROLLER_H + +#include "abstract_client.h" + +#include +#include +#include +#include +#include +#include + +class RemoteClient; +class ServerInfo_User; +class DlgConnect; + +/** + * Owns the RemoteClient and its worker thread. + * Encapsulates all connection, authentication, and registration logic so that + * MainWindow only needs to react to high-level signals. + */ +class ConnectionController : public QObject +{ + Q_OBJECT + +public: + explicit ConnectionController(QWidget *dialogParent, QObject *parent = nullptr); + ~ConnectionController() override; + + RemoteClient *client() const + { + return remoteClient; + } + + void registerToServer(); + void forgotPasswordRequest(); + void connectToServer(); + void + connectToServerDirect(const QString &host, unsigned int port, const QString &playerName, const QString &password); + void disconnectFromServer(); + + void refreshWindowTitle() + { + updateWindowTitle(); + } + +signals: + void windowTitleChanged(const QString &title); + + void tabSupervisorStartRequested(const ServerInfo_User &info); + void tabSupervisorStopRequested(); + + // Passes the raw ClientStatus through so MainWindow can drive its own + // action enable/disable logic + void statusChanged(ClientStatus status); + +private slots: + // Slots wired directly to RemoteClient signals + void onStatusChanged(ClientStatus status); + void onUserInfoReceived(const ServerInfo_User &info); + void onLoginError(int r, QString reasonStr, quint32 endTime, const QList &missingFeatures); + void onRegisterAccepted(); + void onRegisterAcceptedNeedsActivate(); + void onRegisterError(int r, QString reasonStr, quint32 endTime); + void onActivateAccepted(); + void onActivateError(); + void onProtocolVersionMismatch(int localVersion, int remoteVersion); + void onNotifyUserAboutUpdate(); + void onConnectionClosedEvent(const Event_ConnectionClosed &event); + void onServerShutdownEvent(const Event_ServerShutdown &event); + void onSocketError(const QString &errorStr); + void onServerTimeout(); + + // Forgot-password flow + void onForgotPasswordSuccess(); + void onForgotPasswordError(); + void onPromptForgotPasswordReset(); + void onPromptForgotPasswordChallenge(); + +private: + void wireClientSignals(); + void updateWindowTitle(); + + /** Parse the server's pipe-delimited username-rule string into HTML. */ + static QString extractInvalidUsernameMessage(QString &in); + + RemoteClient *remoteClient{nullptr}; + QThread *clientThread{nullptr}; + QWidget *dialogParent{nullptr}; // used as parent for QMessageBox / dialog calls + + // Persistent so it can be updated in-place by onServerShutdownEvent + QMessageBox serverShutdownMessageBox; + + // Kept as a member so the forgot-password signal can be wired to it + DlgConnect *dlgConnect{nullptr}; +}; + +#endif // COCKATRICE_REMOTE_CONNECTION_CONTROLLER_H diff --git a/cockatrice/src/interface/window_main.cpp b/cockatrice/src/interface/window_main.cpp index 86e6c1534..2756d0df2 100644 --- a/cockatrice/src/interface/window_main.cpp +++ b/cockatrice/src/interface/window_main.cpp @@ -22,14 +22,9 @@ #include "../client/network/update/client/client_update_checker.h" #include "../client/network/update/client/release_channel.h" #include "../client/settings/cache_settings.h" -#include "../interface/widgets/dialogs/dlg_connect.h" #include "../interface/widgets/dialogs/dlg_edit_tokens.h" -#include "../interface/widgets/dialogs/dlg_forgot_password_challenge.h" -#include "../interface/widgets/dialogs/dlg_forgot_password_request.h" -#include "../interface/widgets/dialogs/dlg_forgot_password_reset.h" #include "../interface/widgets/dialogs/dlg_local_game_options.h" #include "../interface/widgets/dialogs/dlg_manage_sets.h" -#include "../interface/widgets/dialogs/dlg_register.h" #include "../interface/widgets/dialogs/dlg_settings.h" #include "../interface/widgets/dialogs/dlg_startup_card_check.h" #include "../interface/widgets/dialogs/dlg_tip_of_the_day.h" @@ -40,6 +35,8 @@ #include "../main.h" #include "logger.h" #include "version_string.h" +#include "widgets/dialogs/dlg_connect.h" +#include "widgets/server/handle_public_servers.h" #include "widgets/utility/get_text_with_max.h" #include @@ -67,8 +64,6 @@ #include #include #include -#include -#include #include #include @@ -100,59 +95,9 @@ void MainWindow::updateTabMenu(const QList &newMenuList) menuBar()->insertMenu(helpMenu->menuAction(), tabMenu); } -void MainWindow::processConnectionClosedEvent(const Event_ConnectionClosed &event) -{ - client->disconnectFromServer(); - QString reasonStr; - switch (event.reason()) { - case Event_ConnectionClosed::USER_LIMIT_REACHED: - reasonStr = tr("The server has reached its maximum user capacity, please check back later."); - break; - case Event_ConnectionClosed::TOO_MANY_CONNECTIONS: - reasonStr = tr("There are too many concurrent connections from your address."); - break; - case Event_ConnectionClosed::BANNED: { - reasonStr = tr("Banned by moderator"); - if (event.has_end_time()) - reasonStr.append( - "\n" + tr("Expected end time: %1").arg(QDateTime::fromSecsSinceEpoch(event.end_time()).toString())); - else - reasonStr.append("\n" + tr("This ban lasts indefinitely.")); - if (event.has_reason_str()) - reasonStr.append("\n\n" + QString::fromStdString(event.reason_str())); - break; - } - case Event_ConnectionClosed::SERVER_SHUTDOWN: - reasonStr = tr("Scheduled server shutdown."); - break; - case Event_ConnectionClosed::USERNAMEINVALID: - reasonStr = tr("Invalid username."); - break; - case Event_ConnectionClosed::LOGGEDINELSEWERE: - reasonStr = tr("You have been logged out due to logging in at another location."); - break; - default: - reasonStr = QString::fromStdString(event.reason_str()); - } - QMessageBox::critical(this, tr("Connection closed"), - tr("The server has terminated your connection.\nReason: %1").arg(reasonStr)); -} - -void MainWindow::processServerShutdownEvent(const Event_ServerShutdown &event) -{ - serverShutdownMessageBox.setInformativeText(tr("The server is going to be restarted in %n minute(s).\nAll running " - "games will be lost.\nReason for shutdown: %1", - "", event.minutes()) - .arg(QString::fromStdString(event.reason()))); - serverShutdownMessageBox.setIconPixmap(QPixmap("theme:cockatrice").scaled(64, 64)); - serverShutdownMessageBox.setText(tr("Scheduled server shutdown")); - serverShutdownMessageBox.setWindowModality(Qt::ApplicationModal); - serverShutdownMessageBox.setVisible(true); -} - void MainWindow::statusChanged(ClientStatus _status) { - setClientStatusTitle(); + connectionController->refreshWindowTitle(); switch (_status) { case StatusDisconnected: tabSupervisor->stop(); @@ -177,51 +122,16 @@ void MainWindow::statusChanged(ClientStatus _status) } } -void MainWindow::userInfoReceived(const ServerInfo_User &info) -{ - tabSupervisor->start(info); -} - -void MainWindow::registerAccepted() -{ - QMessageBox::information(this, tr("Success"), tr("Registration accepted.\nWill now login.")); -} - -void MainWindow::registerAcceptedNeedsActivate() -{ - // nothing -} - -void MainWindow::activateAccepted() -{ - QMessageBox::information(this, tr("Success"), tr("Account activation accepted.\nWill now login.")); -} - // Actions void MainWindow::actConnect() { - dlgConnect = new DlgConnect(this); - connect(dlgConnect, &DlgConnect::sigStartForgotPasswordRequest, this, &MainWindow::actForgotPasswordRequest); - - if (dlgConnect->exec()) { - client->connectToServer(dlgConnect->getHost(), static_cast(dlgConnect->getPort()), - dlgConnect->getPlayerName(), dlgConnect->getPassword()); - } -} - -void MainWindow::actRegister() -{ - DlgRegister dlg(this); - if (dlg.exec()) { - client->registerToServer(dlg.getHost(), static_cast(dlg.getPort()), dlg.getPlayerName(), - dlg.getPassword(), dlg.getEmail(), dlg.getCountry(), dlg.getRealName()); - } + connectionController->connectToServer(); } void MainWindow::actDisconnect() { - client->disconnectFromServer(); + connectionController->disconnectFromServer(); } void MainWindow::actSinglePlayer() @@ -373,292 +283,9 @@ void MainWindow::actOpenSettingsFolder() QDesktopServices::openUrl(QUrl::fromLocalFile(dir)); } -void MainWindow::serverTimeout() -{ - QMessageBox::critical(this, tr("Error"), tr("Server timeout")); - actConnect(); -} - -void MainWindow::loginError(Response::ResponseCode r, - QString reasonStr, - quint32 endTime, - QList missingFeatures) -{ - switch (r) { - case Response::RespClientUpdateRequired: { - QString formattedMissingFeatures; - formattedMissingFeatures = "Missing Features: "; - for (int i = 0; i < missingFeatures.size(); ++i) - formattedMissingFeatures.append(QString("\n %1").arg(QChar(0x2022)) + " " + - missingFeatures.value(i)); - - QMessageBox msgBox; - msgBox.setIcon(QMessageBox::Critical); - msgBox.setWindowTitle(tr("Failed Login")); - msgBox.setText(tr("Your client seems to be missing features this server requires for connection.") + - "\n\n" + tr("To update your client, go to 'Help -> Check for Client Updates'.")); - msgBox.setDetailedText(formattedMissingFeatures); - msgBox.exec(); - break; - } - case Response::RespWrongPassword: - QMessageBox::critical( - this, tr("Error"), - tr("Incorrect username or password. Please check your authentication information and try again.")); - break; - case Response::RespWouldOverwriteOldSession: - QMessageBox::critical(this, tr("Error"), - tr("There is already an active session using this user name.\nPlease close that " - "session first and re-login.")); - break; - case Response::RespUserIsBanned: { - QString bannedStr; - if (endTime) - bannedStr = tr("You are banned until %1.").arg(QDateTime::fromSecsSinceEpoch(endTime).toString()); - else - bannedStr = tr("You are banned indefinitely."); - if (!reasonStr.isEmpty()) - bannedStr.append("\n\n" + reasonStr); - - QMessageBox::critical(this, tr("Error"), bannedStr); - break; - } - case Response::RespUsernameInvalid: { - QMessageBox::critical(this, tr("Error"), extractInvalidUsernameMessage(reasonStr)); - break; - } - case Response::RespRegistrationRequired: - if (QMessageBox::question(this, tr("Error"), - tr("This server requires user registration. Do you want to register now?"), - QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { - actRegister(); - } - break; - case Response::RespClientIdRequired: - QMessageBox::critical( - this, tr("Error"), - tr("This server requires client IDs. Your client is either failing to generate an ID or you are " - "running a modified client.\nPlease close and reopen your client to try again.")); - break; - case Response::RespContextError: - QMessageBox::critical(this, tr("Error"), - tr("An internal error has occurred, please close and reopen Cockatrice before trying " - "again.\nIf the error persists, ensure you are running the latest version of the " - "software and if needed contact the software developers.")); - break; - case Response::RespAccountNotActivated: { - bool ok = false; - QString token = getTextWithMax(this, tr("Account activation"), - tr("Your account has not been activated yet.\nYou need to provide " - "the activation token received in the activation email."), - QLineEdit::Normal, QString(), &ok); - if (ok && !token.isEmpty()) { - client->activateToServer(token); - return; - } - client->disconnectFromServer(); - break; - } - case Response::RespServerFull: { - QMessageBox::critical(this, tr("Server Full"), - tr("The server has reached its maximum user capacity, please check back later.")); - break; - } - default: - QMessageBox::critical(this, tr("Error"), - tr("Unknown login error: %1").arg(static_cast(r)) + - tr("\nThis usually means that your client version is out of date, and the server " - "sent a reply your client doesn't understand.")); - break; - } - actConnect(); -} - -QString MainWindow::extractInvalidUsernameMessage(QString &in) -{ - QString out = tr("Invalid username.") + "
"; - QStringList rules = in.split(QChar('|')); - if (rules.size() == 7 || rules.size() == 9) { - out += tr("Your username must respect these rules:") + "
    "; - - out += "
  • " + tr("is %1 - %2 characters long").arg(rules.at(0)).arg(rules.at(1)) + "
  • "; - out += "
  • " + tr("can %1 contain lowercase characters").arg((rules.at(2).toInt() > 0) ? "" : tr("NOT")) + - "
  • "; - out += "
  • " + tr("can %1 contain uppercase characters").arg((rules.at(3).toInt() > 0) ? "" : tr("NOT")) + - "
  • "; - out += - "
  • " + tr("can %1 contain numeric characters").arg((rules.at(4).toInt() > 0) ? "" : tr("NOT")) + "
  • "; - - if (rules.at(6).size() > 0) - out += "
  • " + tr("can contain the following punctuation: %1").arg(rules.at(6).toHtmlEscaped()) + "
  • "; - - out += "
  • " + - tr("first character can %1 be a punctuation mark").arg((rules.at(5).toInt() > 0) ? "" : tr("NOT")) + - "
  • "; - - if (rules.size() == 9) { - if (rules.at(7).size() > 0) { - QString words = rules.at(7).toHtmlEscaped(); - if (words.startsWith("\n")) { - out += tr("no unacceptable language as specified by these server rules:", - "note that the following lines will not be translated"); - for (QString &line : words.split("\n", Qt::SkipEmptyParts)) { - out += "
  • " + line + "
  • "; - } - } else { - out += "
  • " + tr("can not contain any of the following words: %1").arg(words) + "
  • "; - } - } - - if (rules.at(8).size() > 0) - out += "
  • " + - tr("can not match any of the following expressions: %1").arg(rules.at(8).toHtmlEscaped()) + - "
  • "; - } - - out += "
"; - } else { - out += tr("You may only use A-Z, a-z, 0-9, _, ., and - in your username."); - } - - return out; -} - -void MainWindow::registerError(Response::ResponseCode r, QString reasonStr, quint32 endTime) -{ - switch (r) { - case Response::RespRegistrationDisabled: - QMessageBox::critical(this, tr("Registration denied"), - tr("Registration is currently disabled on this server")); - break; - case Response::RespUserAlreadyExists: - QMessageBox::critical(this, tr("Registration denied"), - tr("There is already an existing account with the same user name.")); - break; - case Response::RespEmailRequiredToRegister: - QMessageBox::critical(this, tr("Registration denied"), - tr("It's mandatory to specify a valid email address when registering.")); - break; - case Response::RespEmailBlackListed: - if (reasonStr.isEmpty()) { - reasonStr = - "The email address provider used during registration has been blocked from use on this server."; - } - QMessageBox::critical(this, tr("Registration denied"), reasonStr); - break; - case Response::RespTooManyRequests: - QMessageBox::critical( - this, tr("Registration denied"), - tr("It appears you are attempting to register a new account on this server yet you already have an " - "account registered with the email provided. This server restricts the number of accounts a user " - "can register per address. Please contact the server operator for further assistance or to obtain " - "your credential information.")); - break; - case Response::RespPasswordTooShort: - QMessageBox::critical(this, tr("Registration denied"), tr("Password too short.")); - break; - case Response::RespUserIsBanned: { - QString bannedStr; - if (endTime) - bannedStr = tr("You are banned until %1.").arg(QDateTime::fromSecsSinceEpoch(endTime).toString()); - else - bannedStr = tr("You are banned indefinitely."); - if (!reasonStr.isEmpty()) - bannedStr.append("\n\n" + reasonStr); - - QMessageBox::critical(this, tr("Error"), bannedStr); - break; - } - case Response::RespUsernameInvalid: { - QMessageBox::critical(this, tr("Error"), extractInvalidUsernameMessage(reasonStr)); - break; - } - case Response::RespRegistrationFailed: - QMessageBox::critical(this, tr("Error"), tr("Registration failed for a technical problem on the server.")); - break; - case Response::RespNotConnected: - QMessageBox::critical(this, tr("Error"), tr("The connection to the server has been lost.")); - break; - default: - QMessageBox::critical(this, tr("Error"), - tr("Unknown registration error: %1").arg(static_cast(r)) + - tr("\nThis usually means that your client version is out of date, and the server " - "sent a reply your client doesn't understand.")); - } - actRegister(); -} - -void MainWindow::activateError() -{ - QMessageBox::critical(this, tr("Error"), tr("Account activation failed")); - client->disconnectFromServer(); - actConnect(); -} - -void MainWindow::socketError(const QString &errorStr) -{ - QMessageBox::critical(this, tr("Error"), tr("Socket error: %1").arg(errorStr)); - actConnect(); -} - -void MainWindow::protocolVersionMismatch(int localVersion, int remoteVersion) -{ - if (localVersion > remoteVersion) - QMessageBox::critical(this, tr("Error"), - tr("You are trying to connect to an obsolete server. Please downgrade your Cockatrice " - "version or connect to a suitable server.\nLocal version is %1, remote version is %2.") - .arg(localVersion) - .arg(remoteVersion)); - else - QMessageBox::critical(this, tr("Error"), - tr("Your Cockatrice client is obsolete. Please update your Cockatrice version.\nLocal " - "version is %1, remote version is %2.") - .arg(localVersion) - .arg(remoteVersion)); -} - -void MainWindow::setClientStatusTitle() -{ - switch (client->getStatus()) { - case StatusConnecting: - setWindowTitle(appName + " - " + tr("Connecting to %1...").arg(client->peerName())); - break; - case StatusRegistering: - setWindowTitle(appName + " - " + - tr("Registering to %1 as %2...").arg(client->peerName()).arg(client->getUserName())); - break; - case StatusDisconnected: - setWindowTitle(appName + " - " + tr("Disconnected")); - break; - case StatusLoggingIn: - setWindowTitle(appName + " - " + tr("Connected, logging in at %1").arg(client->peerName())); - break; - case StatusLoggedIn: - setWindowTitle(client->getUserName() + "@" + client->peerName()); - break; - case StatusRequestingForgotPassword: - setWindowTitle( - appName + " - " + - tr("Requesting forgotten password to %1 as %2...").arg(client->peerName()).arg(client->getUserName())); - break; - case StatusSubmitForgotPasswordChallenge: - setWindowTitle( - appName + " - " + - tr("Requesting forgotten password to %1 as %2...").arg(client->peerName()).arg(client->getUserName())); - break; - case StatusSubmitForgotPasswordReset: - setWindowTitle( - appName + " - " + - tr("Requesting forgotten password to %1 as %2...").arg(client->peerName()).arg(client->getUserName())); - break; - default: - setWindowTitle(appName); - } -} - void MainWindow::retranslateUi() { - setClientStatusTitle(); + connectionController->refreshWindowTitle(); aConnect->setText(tr("&Connect...")); aDisconnect->setText(tr("&Disconnect")); @@ -717,9 +344,9 @@ void MainWindow::createActions() aFullScreen->setCheckable(true); connect(aFullScreen, &QAction::toggled, this, &MainWindow::actFullScreen); aRegister = new QAction(this); - connect(aRegister, &QAction::triggered, this, &MainWindow::actRegister); + connect(aRegister, &QAction::triggered, connectionController, &ConnectionController::registerToServer); aForgotPassword = new QAction(this); - connect(aForgotPassword, &QAction::triggered, this, &MainWindow::actForgotPasswordRequest); + connect(aForgotPassword, &QAction::triggered, connectionController, &ConnectionController::forgotPasswordRequest); aSettings = new QAction(this); connect(aSettings, &QAction::triggered, this, &MainWindow::actSettings); aExit = new QAction(this); @@ -844,38 +471,22 @@ MainWindow::MainWindow(QWidget *parent) &MainWindow::pixmapCacheSizeChanged); pixmapCacheSizeChanged(SettingsCache::instance().getPixmapCacheSize()); - client = new RemoteClient(nullptr, &SettingsCache::instance()); - connect(client, &RemoteClient::connectionClosedEventReceived, this, &MainWindow::processConnectionClosedEvent); - connect(client, &RemoteClient::serverShutdownEventReceived, this, &MainWindow::processServerShutdownEvent); - connect(client, &RemoteClient::loginError, this, &MainWindow::loginError); - connect(client, &RemoteClient::socketError, this, &MainWindow::socketError); - connect(client, &RemoteClient::serverTimeout, this, &MainWindow::serverTimeout); - connect(client, &RemoteClient::statusChanged, this, &MainWindow::statusChanged); - connect(client, &RemoteClient::protocolVersionMismatch, this, &MainWindow::protocolVersionMismatch); - connect(client, &RemoteClient::userInfoChanged, this, &MainWindow::userInfoReceived, Qt::BlockingQueuedConnection); - connect(client, &RemoteClient::notifyUserAboutUpdate, this, &MainWindow::notifyUserAboutUpdate); - connect(client, &RemoteClient::registerAccepted, this, &MainWindow::registerAccepted); - connect(client, &RemoteClient::registerAcceptedNeedsActivate, this, &MainWindow::registerAcceptedNeedsActivate); - connect(client, &RemoteClient::registerError, this, &MainWindow::registerError); - connect(client, &RemoteClient::activateAccepted, this, &MainWindow::activateAccepted); - connect(client, &RemoteClient::activateError, this, &MainWindow::activateError); - connect(client, &RemoteClient::sigForgotPasswordSuccess, this, &MainWindow::forgotPasswordSuccess); - connect(client, &RemoteClient::sigForgotPasswordError, this, &MainWindow::forgotPasswordError); - connect(client, &RemoteClient::sigPromptForForgotPasswordReset, this, &MainWindow::promptForgotPasswordReset); - connect(client, &RemoteClient::sigPromptForForgotPasswordChallenge, this, - &MainWindow::promptForgotPasswordChallenge); - - clientThread = new QThread(this); - client->moveToThread(clientThread); - clientThread->start(); + connectionController = new ConnectionController(this, this); createActions(); createMenus(); - tabSupervisor = new TabSupervisor(client, tabsMenu, this); + connect(connectionController, &ConnectionController::windowTitleChanged, this, &MainWindow::setWindowTitle); + connect(connectionController, &ConnectionController::statusChanged, this, &MainWindow::statusChanged); + + tabSupervisor = new TabSupervisor(connectionController->client(), tabsMenu, this); connect(tabSupervisor, &TabSupervisor::setMenu, this, &MainWindow::updateTabMenu); connect(tabSupervisor, &TabSupervisor::localGameEnded, this, &MainWindow::localGameEnded); connect(tabSupervisor, &TabSupervisor::showWindowIfHidden, this, &MainWindow::showWindowIfHidden); + connect(connectionController, &ConnectionController::tabSupervisorStartRequested, tabSupervisor, + &TabSupervisor::start); + connect(connectionController, &ConnectionController::tabSupervisorStopRequested, tabSupervisor, + &TabSupervisor::stop); tabSupervisor->initStartupTabs(); setCentralWidget(tabSupervisor); @@ -1043,9 +654,6 @@ MainWindow::~MainWindow() cardUpdateProcess->waitForFinished(1000); cardUpdateProcess = nullptr; } - - client->deleteLater(); - clientThread->wait(); } void MainWindow::createTrayIcon() @@ -1079,14 +687,6 @@ void MainWindow::actShow() }); } -void MainWindow::promptForgotPasswordChallenge() -{ - DlgForgotPasswordChallenge dlg(this); - if (dlg.exec()) - client->submitForgotPasswordChallengeToServer(dlg.getHost(), static_cast(dlg.getPort()), - dlg.getPlayerName(), dlg.getEmail()); -} - void MainWindow::closeEvent(QCloseEvent *event) { // workaround Qt bug where closeEvent gets called twice @@ -1116,13 +716,14 @@ void MainWindow::changeEvent(QEvent *event) bHasActivated = true; if (!connectTo.isEmpty()) { qCInfo(WindowMainStartupAutoconnectLog) << "Command line connect to " << connectTo; - client->connectToServer(connectTo.host(), connectTo.port(), connectTo.userName(), connectTo.password()); + connectionController->connectToServerDirect(connectTo.host(), connectTo.port(), connectTo.userName(), + connectTo.password()); } else if (SettingsCache::instance().servers().getAutoConnect() && !SettingsCache::instance().debug().getLocalGameOnStartup()) { qCInfo(WindowMainStartupAutoconnectLog) << "Attempting auto-connect..."; DlgConnect dlg(this); - client->connectToServer(dlg.getHost(), static_cast(dlg.getPort()), dlg.getPlayerName(), - dlg.getPassword()); + connectionController->connectToServerDirect(dlg.getHost(), static_cast(dlg.getPort()), + dlg.getPlayerName(), dlg.getPassword()); } } } @@ -1381,15 +982,6 @@ void MainWindow::refreshShortcuts() aStatusBar->setShortcuts(shortcuts.getShortcut("MainWindow/aStatusBar")); } -void MainWindow::notifyUserAboutUpdate() -{ - QMessageBox::information( - this, tr("Information"), - tr("This server supports additional features that your client doesn't have.\nThis is most likely not a " - "problem, but this message might mean there is a new version of Cockatrice available or this server is " - "running a custom or pre-release version.\n\nTo update your client, go to Help -> Check for Updates.")); -} - void MainWindow::actOpenCustomFolder() { QString dir = SettingsCache::instance().getCustomPicsPath(); @@ -1490,42 +1082,3 @@ void MainWindow::actEditTokens() dlg.exec(); CardDatabaseManager::getInstance()->saveCustomTokensToFile(); } - -void MainWindow::actForgotPasswordRequest() -{ - DlgForgotPasswordRequest dlg(this); - if (dlg.exec()) - client->requestForgotPasswordToServer(dlg.getHost(), static_cast(dlg.getPort()), - dlg.getPlayerName()); -} - -void MainWindow::forgotPasswordSuccess() -{ - QMessageBox::information( - this, tr("Reset Password"), - tr("Your password has been reset successfully, you can now log in using the new credentials.")); - SettingsCache::instance().servers().setFPHostName(""); - SettingsCache::instance().servers().setFPPort(""); - SettingsCache::instance().servers().setFPPlayerName(""); -} - -void MainWindow::forgotPasswordError() -{ - QMessageBox::warning( - this, tr("Reset Password"), - tr("Failed to reset user account password, please contact the server operator to reset your password.")); - SettingsCache::instance().servers().setFPHostName(""); - SettingsCache::instance().servers().setFPPort(""); - SettingsCache::instance().servers().setFPPlayerName(""); -} - -void MainWindow::promptForgotPasswordReset() -{ - QMessageBox::information(this, tr("Reset Password"), - tr("Activation request received, please check your email for an activation token.")); - DlgForgotPasswordReset dlg(this); - if (dlg.exec()) { - client->submitForgotPasswordResetToServer(dlg.getHost(), static_cast(dlg.getPort()), - dlg.getPlayerName(), dlg.getToken(), dlg.getPassword()); - } -} diff --git a/cockatrice/src/interface/window_main.h b/cockatrice/src/interface/window_main.h index ed6de5b0d..528e6f211 100644 --- a/cockatrice/src/interface/window_main.h +++ b/cockatrice/src/interface/window_main.h @@ -25,6 +25,7 @@ #ifndef WINDOW_H #define WINDOW_H +#include "connection_controller/remote_connection_controller.h" #include "widgets/dialogs/dlg_local_game_options.h" #include @@ -68,38 +69,19 @@ public slots: private slots: void updateTabMenu(const QList &newMenuList); void statusChanged(ClientStatus _status); - void processConnectionClosedEvent(const Event_ConnectionClosed &event); - void processServerShutdownEvent(const Event_ServerShutdown &event); - void serverTimeout(); - void loginError(Response::ResponseCode r, QString reasonStr, quint32 endTime, QList missingFeatures); - void registerError(Response::ResponseCode r, QString reasonStr, quint32 endTime); - void activateError(); - void socketError(const QString &errorStr); - void protocolVersionMismatch(int localVersion, int remoteVersion); - void userInfoReceived(const ServerInfo_User &userInfo); - void registerAccepted(); - void registerAcceptedNeedsActivate(); - void activateAccepted(); void localGameEnded(); void pixmapCacheSizeChanged(int newSizeInMBs); - void notifyUserAboutUpdate(); void actDisconnect(); void actSinglePlayer(); void actWatchReplay(); void actFullScreen(bool checked); - void actRegister(); void actSettings(); - void actForgotPasswordRequest(); void actAbout(); void actTips(); void actUpdate(); void actViewLog(); void actOpenSettingsFolder(); - void forgotPasswordSuccess(); - void forgotPasswordError(); - void promptForgotPasswordReset(); void actShow(); - void promptForgotPasswordChallenge(); void showWindowIfHidden(); void cardUpdateError(QProcess::ProcessError err); @@ -125,7 +107,6 @@ private slots: private: static const QString appName; static const QStringList fileNameFilters; - void setClientStatusTitle(); void retranslateUi(); void createActions(); void createMenus(); @@ -152,14 +133,11 @@ private: TabSupervisor *tabSupervisor; WndSets *wndSets; - RemoteClient *client; - QThread *clientThread; + ConnectionController *connectionController; LocalServer *localServer; bool bHasActivated, askedForDbUpdater; - QMessageBox serverShutdownMessageBox; QProcess *cardUpdateProcess; DlgViewLog *logviewDialog; - DlgConnect *dlgConnect; GameReplay *replay; DlgTipOfTheDay *tip; QUrl connectTo; @@ -180,7 +158,6 @@ public: protected: void closeEvent(QCloseEvent *event) override; void changeEvent(QEvent *event) override; - QString extractInvalidUsernameMessage(QString &in); }; #endif