diff --git a/cockatrice/src/abstractclient.h b/cockatrice/src/abstractclient.h index e683e3ba..df029a1e 100644 --- a/cockatrice/src/abstractclient.h +++ b/cockatrice/src/abstractclient.h @@ -30,6 +30,7 @@ enum ClientStatus { StatusDisconnecting, StatusConnecting, StatusRegistering, + StatusActivating, StatusLoggingIn, StatusLoggedIn, }; @@ -60,6 +61,8 @@ signals: void ignoreListReceived(const QList &ignoreList); void replayAddedEventReceived(const Event_ReplayAdded &event); void registerAccepted(); + void registerAcceptedNeedsActivate(); + void activateAccepted(); void sigQueuePendingCommand(PendingCommand *pend); private: @@ -72,7 +75,7 @@ protected slots: void processProtocolItem(const ServerMessage &item); protected: QMap pendingCommands; - QString userName, password, email, country, realName; + QString userName, password, email, country, realName, token; int gender; void setStatus(ClientStatus _status); int getNewCmdId() { return nextCmdId++; } diff --git a/cockatrice/src/remoteclient.cpp b/cockatrice/src/remoteclient.cpp index aae2df01..13d75a04 100644 --- a/cockatrice/src/remoteclient.cpp +++ b/cockatrice/src/remoteclient.cpp @@ -7,6 +7,7 @@ #include "pb/session_commands.pb.h" #include "pb/response_login.pb.h" #include "pb/response_register.pb.h" +#include "pb/response_activate.pb.h" #include "pb/server_message.pb.h" #include "pb/event_server_identification.pb.h" @@ -30,6 +31,7 @@ RemoteClient::RemoteClient(QObject *parent) connect(this, SIGNAL(sigConnectToServer(QString, unsigned int, QString, QString)), this, SLOT(doConnectToServer(QString, unsigned int, QString, QString))); connect(this, SIGNAL(sigDisconnectFromServer()), this, SLOT(doDisconnectFromServer())); connect(this, SIGNAL(sigRegisterToServer(QString, unsigned int, QString, QString, QString, int, QString, QString)), this, SLOT(doRegisterToServer(QString, unsigned int, QString, QString, QString, int, QString, QString))); + connect(this, SIGNAL(sigActivateToServer(QString)), this, SLOT(doActivateToServer(QString))); } RemoteClient::~RemoteClient() @@ -81,6 +83,24 @@ void RemoteClient::processServerIdentificationEvent(const Event_ServerIdentifica return; } + if(getStatus() == StatusActivating) + { + Command_Activate cmdActivate; + cmdActivate.set_user_name(userName.toStdString()); + cmdActivate.set_token(token.toStdString()); + + PendingCommand *pend = prepareSessionCommand(cmdActivate); + connect(pend, SIGNAL(finished(Response, CommandContainer, QVariant)), this, SLOT(activateResponse(Response))); + sendCommand(pend); + + return; + } + + doLogin(); +} + +void RemoteClient::doLogin() +{ setStatus(StatusLoggingIn); Command_Login cmdLogin; @@ -122,13 +142,34 @@ void RemoteClient::loginResponse(const Response &response) void RemoteClient::registerResponse(const Response &response) { const Response_Register &resp = response.GetExtension(Response_Register::ext); - if (response.response_code() == Response::RespRegistrationAccepted) { - emit registerAccepted(); - } else { - emit registerError(response.response_code(), QString::fromStdString(resp.denied_reason_str()), resp.denied_end_time()); + switch(response.response_code()) + { + case Response::RespRegistrationAccepted: + emit registerAccepted(); + doLogin(); + break; + case Response::RespRegistrationAcceptedNeedsActivation: + emit registerAcceptedNeedsActivate(); + doLogin(); + break; + default: + emit registerError(response.response_code(), QString::fromStdString(resp.denied_reason_str()), resp.denied_end_time()); + setStatus(StatusDisconnecting); + doDisconnectFromServer(); + break; + } +} + +void RemoteClient::activateResponse(const Response &response) +{ + const Response_Activate &resp = response.GetExtension(Response_Activate::ext); + if (response.response_code() == Response::RespActivationAccepted) { + emit activateAccepted(); + + doLogin(); + } else { + emit activateError(); } - setStatus(StatusDisconnecting); - doDisconnectFromServer(); } void RemoteClient::readData() @@ -201,6 +242,9 @@ void RemoteClient::doConnectToServer(const QString &hostname, unsigned int port, userName = _userName; password = _password; + lastHostname = hostname; + lastPort = port; + socket->connectToHost(hostname, port); setStatus(StatusConnecting); } @@ -215,11 +259,23 @@ void RemoteClient::doRegisterToServer(const QString &hostname, unsigned int port gender = _gender; country = _country; realName = _realname; + lastHostname = hostname; + lastPort = port; socket->connectToHost(hostname, port); setStatus(StatusRegistering); } +void RemoteClient::doActivateToServer(const QString &_token) +{ + doDisconnectFromServer(); + + token = _token; + + socket->connectToHost(lastHostname, lastPort); + setStatus(StatusActivating); +} + void RemoteClient::doDisconnectFromServer() { timer->stop(); @@ -275,6 +331,11 @@ void RemoteClient::registerToServer(const QString &hostname, unsigned int port, emit sigRegisterToServer(hostname, port, _userName, _password, _email, _gender, _country, _realname); } +void RemoteClient::activateToServer(const QString &_token) +{ + emit sigActivateToServer(_token); +} + void RemoteClient::disconnectFromServer() { emit sigDisconnectFromServer(); diff --git a/cockatrice/src/remoteclient.h b/cockatrice/src/remoteclient.h index 6359f6f4..c1478732 100644 --- a/cockatrice/src/remoteclient.h +++ b/cockatrice/src/remoteclient.h @@ -13,11 +13,13 @@ signals: void serverTimeout(); void loginError(Response::ResponseCode resp, QString reasonStr, quint32 endTime); void registerError(Response::ResponseCode resp, QString reasonStr, quint32 endTime); + void activateError(); void socketError(const QString &errorString); void protocolVersionMismatch(int clientVersion, int serverVersion); void protocolError(); void sigConnectToServer(const QString &hostname, unsigned int port, const QString &_userName, const QString &_password); void sigRegisterToServer(const QString &hostname, unsigned int port, const QString &_userName, const QString &_password, const QString &_email, const int _gender, const QString &_country, const QString &_realname); + void sigActivateToServer(const QString &_token); void sigDisconnectFromServer(); private slots: void slotConnected(); @@ -28,9 +30,13 @@ private slots: void processConnectionClosedEvent(const Event_ConnectionClosed &event); void loginResponse(const Response &response); void registerResponse(const Response &response); + void activateResponse(const Response &response); void doConnectToServer(const QString &hostname, unsigned int port, const QString &_userName, const QString &_password); void doRegisterToServer(const QString &hostname, unsigned int port, const QString &_userName, const QString &_password, const QString &_email, const int _gender, const QString &_country, const QString &_realname); + void doLogin(); void doDisconnectFromServer(); + void doActivateToServer(const QString &_token); + private: static const int maxTimeout = 10; int timeRunning, lastDataReceived; @@ -42,6 +48,8 @@ private: QTimer *timer; QTcpSocket *socket; + QString lastHostname; + int lastPort; protected slots: void sendCommandContainer(const CommandContainer &cont); public: @@ -50,7 +58,7 @@ public: QString peerName() const { return socket->peerName(); } void connectToServer(const QString &hostname, unsigned int port, const QString &_userName, const QString &_password); void registerToServer(const QString &hostname, unsigned int port, const QString &_userName, const QString &_password, const QString &_email, const int _gender, const QString &_country, const QString &_realname); - + void activateToServer(const QString &_token); void disconnectFromServer(); }; diff --git a/cockatrice/src/window_main.cpp b/cockatrice/src/window_main.cpp index c19f1c9d..896d7821 100644 --- a/cockatrice/src/window_main.cpp +++ b/cockatrice/src/window_main.cpp @@ -126,8 +126,17 @@ void MainWindow::userInfoReceived(const ServerInfo_User &info) void MainWindow::registerAccepted() { - QMessageBox::information(this, tr("Success"), tr("Registration accepted.\nNow check your email for instructions on how to activate your account.")); - actConnect(); + 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 @@ -299,11 +308,20 @@ void MainWindow::loginError(Response::ResponseCode r, QString reasonStr, quint32 actRegister(); } break; - case Response::RespAccountNotActivated: - QMessageBox::critical(this, tr("Error"), tr("Your account has not been activated yet.")); + case Response::RespAccountNotActivated: { + bool ok = false; + QString token = QInputDialog::getText(this, 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()) + { + client->activateToServer(token); + return; + } + client->disconnectFromServer(); break; + } default: QMessageBox::critical(this, tr("Error"), tr("Unknown login error: %1").arg(static_cast(r))); + break; } actConnect(); } @@ -350,6 +368,13 @@ void MainWindow::registerError(Response::ResponseCode r, QString reasonStr, quin 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)); @@ -488,7 +513,10 @@ MainWindow::MainWindow(QWidget *parent) connect(client, SIGNAL(userInfoChanged(const ServerInfo_User &)), this, SLOT(userInfoReceived(const ServerInfo_User &)), Qt::BlockingQueuedConnection); connect(client, SIGNAL(registerAccepted()), this, SLOT(registerAccepted())); + connect(client, SIGNAL(registerAcceptedNeedsActivate()), this, SLOT(registerAcceptedNeedsActivate())); connect(client, SIGNAL(registerError(Response::ResponseCode, QString, quint32)), this, SLOT(registerError(Response::ResponseCode, QString, quint32))); + connect(client, SIGNAL(activateAccepted()), this, SLOT(activateAccepted())); + connect(client, SIGNAL(activateError()), this, SLOT(activateError())); clientThread = new QThread(this); client->moveToThread(clientThread); diff --git a/cockatrice/src/window_main.h b/cockatrice/src/window_main.h index 6b1660a7..c60a2db3 100644 --- a/cockatrice/src/window_main.h +++ b/cockatrice/src/window_main.h @@ -44,10 +44,13 @@ private slots: void serverTimeout(); void loginError(Response::ResponseCode r, QString reasonStr, quint32 endTime); 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); diff --git a/common/pb/CMakeLists.txt b/common/pb/CMakeLists.txt index e698c95f..db5cd130 100644 --- a/common/pb/CMakeLists.txt +++ b/common/pb/CMakeLists.txt @@ -114,6 +114,7 @@ SET(PROTO_FILES isl_message.proto moderator_commands.proto move_card_to_zone.proto + response_activate.proto response_deck_download.proto response_deck_list.proto response_deck_upload.proto diff --git a/common/pb/response.proto b/common/pb/response.proto index ccd09389..4955bed5 100644 --- a/common/pb/response.proto +++ b/common/pb/response.proto @@ -32,6 +32,9 @@ message Response { RespAccountNotActivated = 28; // Client attempted to log into a registered username but the account hasn't been activated RespRegistrationDisabled = 29; // Server does not allow clients to register RespRegistrationFailed = 30; // Server accepted a reg request but failed to perform the registration + RespActivationAccepted = 31; // Server accepted a reg user activation token + RespActivationFailed = 32; // Server didn't accept a reg user activation token + RespRegistrationAcceptedNeedsActivation = 33; // Server accepted cient registration, but it will need token activation } enum ResponseType { JOIN_ROOM = 1000; @@ -44,6 +47,7 @@ message Response { DECK_DOWNLOAD = 1007; DECK_UPLOAD = 1008; REGISTER = 1009; + ACTIVATE = 1010; REPLAY_LIST = 1100; REPLAY_DOWNLOAD = 1101; } diff --git a/common/pb/response_activate.proto b/common/pb/response_activate.proto new file mode 100644 index 00000000..25667534 --- /dev/null +++ b/common/pb/response_activate.proto @@ -0,0 +1,7 @@ +import "response.proto"; + +message Response_Activate { + extend Response { + optional Response_Activate ext = 1010; + } +} \ No newline at end of file diff --git a/common/pb/session_commands.proto b/common/pb/session_commands.proto index be5cc1db..11e5ce6f 100644 --- a/common/pb/session_commands.proto +++ b/common/pb/session_commands.proto @@ -19,6 +19,7 @@ message SessionCommand { LIST_ROOMS = 1014; JOIN_ROOM = 1015; REGISTER = 1016; + ACTIVATE = 1017; REPLAY_LIST = 1100; REPLAY_DOWNLOAD = 1101; REPLAY_MODIFY_MATCH = 1102; @@ -115,3 +116,14 @@ message Command_Register { optional string country = 5; optional string real_name = 6; } + +// User wants to activate an account +message Command_Activate { + extend SessionCommand { + optional Command_Activate ext = 1017; + } + // User name client wants to activate + required string user_name = 1; + // Activation token + required string token = 2; +} diff --git a/common/server.cpp b/common/server.cpp index 48dd54e2..1e3991c3 100644 --- a/common/server.cpp +++ b/common/server.cpp @@ -208,9 +208,22 @@ RegistrationResult Server::registerUserAccount(const QString &ipAddress, const C if(password.length() < 6) return PasswordTooShort; - bool regSucceeded = databaseInterface->registerUser(userName, realName, gender, password, emailAddress, country, false); + bool regSucceeded = databaseInterface->registerUser(userName, realName, gender, password, emailAddress, country, !requireEmailForRegistration); - return regSucceeded ? Accepted : Failed; + if(regSucceeded) + return requireEmailForRegistration ? AcceptedNeedsActivation : Accepted; + else + return Failed; +} + +bool Server::activateUserAccount(const Command_Activate &cmd) +{ + QString userName = QString::fromStdString(cmd.user_name()); + QString token = QString::fromStdString(cmd.token()); + + Server_DatabaseInterface *databaseInterface = getDatabaseInterface(); + + return databaseInterface->activateUser(userName, token); } bool Server::tooManyRegistrationAttempts(const QString &ipAddress) diff --git a/common/server.h b/common/server.h index 736ef582..827b38f4 100644 --- a/common/server.h +++ b/common/server.h @@ -29,7 +29,7 @@ class CommandContainer; class Command_JoinGame; enum AuthenticationResult { NotLoggedIn, PasswordRight, UnknownUser, WouldOverwriteOldSession, UserIsBanned, UsernameInvalid, RegistrationRequired, UserIsInactive }; -enum RegistrationResult { Accepted, UserAlreadyExists, EmailRequired, TooManyRequests, InvalidUsername, ClientIsBanned, RegistrationDisabled, Failed, PasswordTooShort }; +enum RegistrationResult { Accepted, UserAlreadyExists, EmailRequired, TooManyRequests, InvalidUsername, ClientIsBanned, RegistrationDisabled, Failed, PasswordTooShort, AcceptedNeedsActivation }; class Server : public QObject { @@ -57,6 +57,7 @@ public: * @return RegistrationResult member indicating whether it succeeded or failed. */ RegistrationResult registerUserAccount(const QString &ipAddress, const Command_Register &cmd, QString &banReason, int &banSecondsRemaining); + bool activateUserAccount(const Command_Activate &cmd); bool tooManyRegistrationAttempts(const QString &ipAddress); const QMap &getRooms() { return rooms; } diff --git a/common/server_database_interface.h b/common/server_database_interface.h index 0cabe867..d809b1ff 100644 --- a/common/server_database_interface.h +++ b/common/server_database_interface.h @@ -39,6 +39,7 @@ public: virtual bool getRequireRegistration() { return false; } virtual bool registerUser(const QString & /* userName */, const QString & /* realName */, ServerInfo_User_Gender const & /* gender */, const QString & /* password */, const QString & /* emailAddress */, const QString & /* country */, bool /* active = false */) { return false; } + virtual bool activateUser(const QString & /* userName */, const QString & /* token */) { return false; } enum LogMessage_TargetType { MessageTargetRoom, MessageTargetGame, MessageTargetChat, MessageTargetIslRoom }; virtual void logMessage(const int /* senderId */, const QString & /* senderName */, const QString & /* senderIp */, const QString & /* logMessage */, LogMessage_TargetType /* targetType */, const int /* targetId */, const QString & /* targetName */) { }; diff --git a/common/server_protocolhandler.cpp b/common/server_protocolhandler.cpp index 9a213108..608f8716 100644 --- a/common/server_protocolhandler.cpp +++ b/common/server_protocolhandler.cpp @@ -146,6 +146,7 @@ Response::ResponseCode Server_ProtocolHandler::processSessionCommandContainer(co case SessionCommand::PING: resp = cmdPing(sc.GetExtension(Command_Ping::ext), rc); break; case SessionCommand::LOGIN: resp = cmdLogin(sc.GetExtension(Command_Login::ext), rc); break; case SessionCommand::REGISTER: resp = cmdRegisterAccount(sc.GetExtension(Command_Register::ext), rc); break; + case SessionCommand::ACTIVATE: resp = cmdActivateAccount(sc.GetExtension(Command_Activate::ext), rc); break; case SessionCommand::MESSAGE: resp = cmdMessage(sc.GetExtension(Command_Message::ext), rc); break; case SessionCommand::GET_GAMES_OF_USER: resp = cmdGetGamesOfUser(sc.GetExtension(Command_GetGamesOfUser::ext), rc); break; case SessionCommand::GET_USER_INFO: resp = cmdGetUserInfo(sc.GetExtension(Command_GetUserInfo::ext), rc); break; @@ -437,8 +438,11 @@ Response::ResponseCode Server_ProtocolHandler::cmdRegisterAccount(const Command_ switch (result) { case RegistrationDisabled: return Response::RespRegistrationDisabled; - case Accepted: + case Accepted: return Response::RespRegistrationAccepted; + case AcceptedNeedsActivation: + // TODO SEND EMAIL WITH TOKEN TO THE USER + return Response::RespRegistrationAcceptedNeedsActivation; case UserAlreadyExists: return Response::RespUserAlreadyExists; case EmailRequired: @@ -463,6 +467,18 @@ Response::ResponseCode Server_ProtocolHandler::cmdRegisterAccount(const Command_ return Response::RespInvalidCommand; } +Response::ResponseCode Server_ProtocolHandler::cmdActivateAccount(const Command_Activate &cmd, ResponseContainer &rc) +{ + if(server->activateUserAccount(cmd)) + { + qDebug() << "Accepted activation for user" << QString::fromStdString(cmd.user_name()); + return Response::RespActivationAccepted; + } else { + qDebug() << "Failed activation for user" << QString::fromStdString(cmd.user_name()); + return Response::RespActivationFailed; + } +} + Response::ResponseCode Server_ProtocolHandler::cmdMessage(const Command_Message &cmd, ResponseContainer &rc) { if (authState == NotLoggedIn) diff --git a/common/server_protocolhandler.h b/common/server_protocolhandler.h index 7ea34cf8..b819d9b3 100644 --- a/common/server_protocolhandler.h +++ b/common/server_protocolhandler.h @@ -61,6 +61,7 @@ private: Response::ResponseCode cmdPing(const Command_Ping &cmd, ResponseContainer &rc); Response::ResponseCode cmdLogin(const Command_Login &cmd, ResponseContainer &rc); Response::ResponseCode cmdRegisterAccount(const Command_Register &cmd, ResponseContainer &rc); + Response::ResponseCode cmdActivateAccount(const Command_Activate &cmd, ResponseContainer &rc); Response::ResponseCode cmdMessage(const Command_Message &cmd, ResponseContainer &rc); Response::ResponseCode cmdGetGamesOfUser(const Command_GetGamesOfUser &cmd, ResponseContainer &rc); Response::ResponseCode cmdGetUserInfo(const Command_GetUserInfo &cmd, ResponseContainer &rc); diff --git a/servatrice/servatrice.ini.example b/servatrice/servatrice.ini.example index d9cc7629..27a3e2f1 100644 --- a/servatrice/servatrice.ini.example +++ b/servatrice/servatrice.ini.example @@ -60,7 +60,9 @@ regonly=0 ; Enable this feature? Default false. ;enabled=false -; Require users to provide an email address in order to register. Default true. +; Require users to provide an email address in order to register. Newly registered users will receive an +; activation token by email, and will be required to input back this token on cockatrice at the first login +; to get their account activated. Default true. ;requireemail=true diff --git a/servatrice/src/passwordhasher.cpp b/servatrice/src/passwordhasher.cpp index b02d8e9b..38528a1b 100644 --- a/servatrice/src/passwordhasher.cpp +++ b/servatrice/src/passwordhasher.cpp @@ -70,3 +70,8 @@ QString PasswordHasher::generateRandomSalt(const int len) return ret; } + +QString PasswordHasher::generateActivationToken() +{ + return QCryptographicHash::hash(generateRandomSalt().toUtf8(), QCryptographicHash::Md5).toBase64().left(16); +} \ No newline at end of file diff --git a/servatrice/src/passwordhasher.h b/servatrice/src/passwordhasher.h index ffe21a9d..4160cb0f 100644 --- a/servatrice/src/passwordhasher.h +++ b/servatrice/src/passwordhasher.h @@ -8,6 +8,7 @@ public: static void initialize(); static QString computeHash(const QString &password, const QString &salt); static QString generateRandomSalt(const int len = 16); + static QString generateActivationToken(); }; #endif diff --git a/servatrice/src/servatrice_database_interface.cpp b/servatrice/src/servatrice_database_interface.cpp index 26d9a4f5..e5ff7d1e 100644 --- a/servatrice/src/servatrice_database_interface.cpp +++ b/servatrice/src/servatrice_database_interface.cpp @@ -117,11 +117,12 @@ bool Servatrice_DatabaseInterface::registerUser(const QString &userName, const Q return false; QString passwordSha512 = PasswordHasher::computeHash(password, PasswordHasher::generateRandomSalt()); + QString token = PasswordHasher::generateActivationToken(); QSqlQuery *query = prepareQuery("insert into {prefix}_users " - "(name, realname, gender, password_sha512, email, country, registrationDate, active) " + "(name, realname, gender, password_sha512, email, country, registrationDate, active, token) " "values " - "(:userName, :realName, :gender, :password_sha512, :email, :country, UTC_TIMESTAMP(), :active)"); + "(:userName, :realName, :gender, :password_sha512, :email, :country, UTC_TIMESTAMP(), :active, :token)"); query->bindValue(":userName", userName); query->bindValue(":realName", realName); query->bindValue(":gender", getGenderChar(gender)); @@ -129,6 +130,7 @@ bool Servatrice_DatabaseInterface::registerUser(const QString &userName, const Q query->bindValue(":email", emailAddress); query->bindValue(":country", country); query->bindValue(":active", active ? 1 : 0); + query->bindValue(":token", token); if (!execSqlQuery(query)) { qDebug() << "Failed to insert user: " << query->lastError() << " sql: " << query->lastQuery(); @@ -138,6 +140,40 @@ bool Servatrice_DatabaseInterface::registerUser(const QString &userName, const Q return true; } +bool Servatrice_DatabaseInterface::activateUser(const QString &userName, const QString &token) +{ + if (!checkSql()) + return false; + + QSqlQuery *activateQuery = prepareQuery("select name from {prefix}_users where active=0 and name=:username and token=:token"); + + activateQuery->bindValue(":username", userName); + activateQuery->bindValue(":token", token); + if (!execSqlQuery(activateQuery)) { + qDebug() << "Account activation failed: SQL error." << activateQuery->lastError()<< " sql: " << activateQuery->lastQuery(); + return false; + } + + if (activateQuery->next()) { + const QString name = activateQuery->value(0).toString(); + // redundant check + if(name == userName) + { + + QSqlQuery *query = prepareQuery("update {prefix}_users set active=1 where name = :userName"); + query->bindValue(":userName", userName); + + if (!execSqlQuery(query)) { + qDebug() << "Failed to activate user: " << query->lastError() << " sql: " << query->lastQuery(); + return false; + } + + return true; + } + } + return false; +} + QChar Servatrice_DatabaseInterface::getGenderChar(ServerInfo_User_Gender const &gender) { switch (gender) { diff --git a/servatrice/src/servatrice_database_interface.h b/servatrice/src/servatrice_database_interface.h index 4e077dac..9bb111ff 100644 --- a/servatrice/src/servatrice_database_interface.h +++ b/servatrice/src/servatrice_database_interface.h @@ -65,6 +65,7 @@ public: bool getRequireRegistration(); bool registerUser(const QString &userName, const QString &realName, ServerInfo_User_Gender const &gender, const QString &password, const QString &emailAddress, const QString &country, bool active = false); + bool activateUser(const QString &userName, const QString &token); void logMessage(const int senderId, const QString &senderName, const QString &senderIp, const QString &logMessage, LogMessage_TargetType targetType, const int targetId, const QString &targetName); };