This commit is contained in:
BruebachL 2026-04-25 10:01:48 -03:00 committed by GitHub
commit bff30f224a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 703 additions and 493 deletions

View file

@ -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

View file

@ -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 <QDateTime>
#include <QLineEdit>
#include <QMessageBox>
#include <QThread>
#include <libcockatrice/network/client/remote/remote_client.h>
#include <libcockatrice/protocol/pb/response.pb.h>
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<QString> mf) {
onLoginError(static_cast<int>(r), rs, et, mf);
});
connect(remoteClient, &RemoteClient::registerError, this,
[this](Response::ResponseCode r, QString rs, quint32 et) { onRegisterError(static_cast<int>(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<unsigned int>(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<unsigned int>(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<unsigned int>(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<QString> &missingFeatures)
{
switch (static_cast<Response::ResponseCode>(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<Response::ResponseCode>(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<unsigned int>(dlg.getPort()),
dlg.getPlayerName(), dlg.getToken(), dlg.getPassword());
}
}
void ConnectionController::onPromptForgotPasswordChallenge()
{
DlgForgotPasswordChallenge dlg(dialogParent);
if (dlg.exec()) {
remoteClient->submitForgotPasswordChallengeToServer(dlg.getHost(), static_cast<unsigned int>(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.") + "<br/>";
QStringList rules = in.split(QChar('|'));
if (rules.size() == 7 || rules.size() == 9) {
out += tr("Your username must respect these rules:") + "<ul>";
out += "<li>" + tr("is %1 - %2 characters long").arg(rules.at(0)).arg(rules.at(1)) + "</li>";
out += "<li>" + tr("can %1 contain lowercase characters").arg((rules.at(2).toInt() > 0) ? "" : tr("NOT")) +
"</li>";
out += "<li>" + tr("can %1 contain uppercase characters").arg((rules.at(3).toInt() > 0) ? "" : tr("NOT")) +
"</li>";
out +=
"<li>" + tr("can %1 contain numeric characters").arg((rules.at(4).toInt() > 0) ? "" : tr("NOT")) + "</li>";
if (rules.at(6).size() > 0)
out += "<li>" + tr("can contain the following punctuation: %1").arg(rules.at(6).toHtmlEscaped()) + "</li>";
out += "<li>" +
tr("first character can %1 be a punctuation mark").arg((rules.at(5).toInt() > 0) ? "" : tr("NOT")) +
"</li>";
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 += "<li>" + line + "</li>";
}
} else {
out += "<li>" + tr("can not contain any of the following words: %1").arg(words) + "</li>";
}
}
if (rules.at(8).size() > 0)
out += "<li>" +
tr("can not match any of the following expressions: %1").arg(rules.at(8).toHtmlEscaped()) +
"</li>";
}
out += "</ul>";
} else {
out += tr("You may only use A-Z, a-z, 0-9, _, ., and - in your username.");
}
return out;
}

View file

@ -0,0 +1,98 @@
#ifndef COCKATRICE_REMOTE_CONNECTION_CONTROLLER_H
#define COCKATRICE_REMOTE_CONNECTION_CONTROLLER_H
#include "abstract_client.h"
#include <QMessageBox>
#include <QObject>
#include <QString>
#include <QThread>
#include <libcockatrice/protocol/pb/event_connection_closed.pb.h>
#include <libcockatrice/protocol/pb/event_server_shutdown.pb.h>
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<QString> &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

View file

@ -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 <QAction>
@ -67,8 +64,6 @@
#include <libcockatrice/network/client/remote/remote_client.h>
#include <libcockatrice/network/server/local/local_server.h>
#include <libcockatrice/network/server/local/local_server_interface.h>
#include <libcockatrice/protocol/pb/event_connection_closed.pb.h>
#include <libcockatrice/protocol/pb/event_server_shutdown.pb.h>
#include <libcockatrice/protocol/pb/game_replay.pb.h>
#include <libcockatrice/protocol/pb/room_commands.pb.h>
@ -100,59 +95,9 @@ void MainWindow::updateTabMenu(const QList<QMenu *> &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<unsigned int>(dlgConnect->getPort()),
dlgConnect->getPlayerName(), dlgConnect->getPassword());
}
}
void MainWindow::actRegister()
{
DlgRegister dlg(this);
if (dlg.exec()) {
client->registerToServer(dlg.getHost(), static_cast<unsigned int>(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<QString> 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<int>(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.") + "<br/>";
QStringList rules = in.split(QChar('|'));
if (rules.size() == 7 || rules.size() == 9) {
out += tr("Your username must respect these rules:") + "<ul>";
out += "<li>" + tr("is %1 - %2 characters long").arg(rules.at(0)).arg(rules.at(1)) + "</li>";
out += "<li>" + tr("can %1 contain lowercase characters").arg((rules.at(2).toInt() > 0) ? "" : tr("NOT")) +
"</li>";
out += "<li>" + tr("can %1 contain uppercase characters").arg((rules.at(3).toInt() > 0) ? "" : tr("NOT")) +
"</li>";
out +=
"<li>" + tr("can %1 contain numeric characters").arg((rules.at(4).toInt() > 0) ? "" : tr("NOT")) + "</li>";
if (rules.at(6).size() > 0)
out += "<li>" + tr("can contain the following punctuation: %1").arg(rules.at(6).toHtmlEscaped()) + "</li>";
out += "<li>" +
tr("first character can %1 be a punctuation mark").arg((rules.at(5).toInt() > 0) ? "" : tr("NOT")) +
"</li>";
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 += "<li>" + line + "</li>";
}
} else {
out += "<li>" + tr("can not contain any of the following words: %1").arg(words) + "</li>";
}
}
if (rules.at(8).size() > 0)
out += "<li>" +
tr("can not match any of the following expressions: %1").arg(rules.at(8).toHtmlEscaped()) +
"</li>";
}
out += "</ul>";
} 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<int>(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<unsigned int>(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<unsigned int>(dlg.getPort()), dlg.getPlayerName(),
dlg.getPassword());
connectionController->connectToServerDirect(dlg.getHost(), static_cast<unsigned int>(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<unsigned int>(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<unsigned int>(dlg.getPort()),
dlg.getPlayerName(), dlg.getToken(), dlg.getPassword());
}
}

View file

@ -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 <QList>
@ -68,38 +69,19 @@ public slots:
private slots:
void updateTabMenu(const QList<QMenu *> &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<QString> 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