Merge branch 'master' into feature/docs
This commit is contained in:
commit
c13a2d06f9
@ -10,4 +10,8 @@ Requires Qt >= 5.10, and Qt websockets
|
|||||||
make
|
make
|
||||||
```
|
```
|
||||||
|
|
||||||
Copyright © scatterflower 2021
|
Copyright © scatterflower 2020-2021
|
||||||
|
|
||||||
|
Copyright © Salanto 2021
|
||||||
|
|
||||||
|
Copyright © in1tiate 2021
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
[Basement]
|
[0:Basement]
|
||||||
background=gs4
|
background=gs4
|
||||||
protected_area=true
|
protected_area=true
|
||||||
iniswap_allowed=false
|
iniswap_allowed=false
|
||||||
evidence_mod=cm
|
evidence_mod=cm
|
||||||
|
|
||||||
[Courtroom 1]
|
[1:Courtroom 1]
|
||||||
background=gs4
|
background=gs4
|
||||||
protected_area=false
|
protected_area=false
|
||||||
iniswap_allowed=true
|
iniswap_allowed=true
|
||||||
|
@ -9,6 +9,7 @@ ms_port=27016
|
|||||||
port=27016
|
port=27016
|
||||||
server_description=This is a placeholder server description. Tell the world of AO who you are here!
|
server_description=This is a placeholder server description. Tell the world of AO who you are here!
|
||||||
server_name=An Unnamed Server
|
server_name=An Unnamed Server
|
||||||
|
motd=MOTD is not set.
|
||||||
webao_enable=true
|
webao_enable=true
|
||||||
webao_port=27017
|
webao_port=27017
|
||||||
auth=simple
|
auth=simple
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
#include <QHostAddress>
|
#include <QHostAddress>
|
||||||
#include <QTcpSocket>
|
#include <QTcpSocket>
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QRegExp>
|
#include <QRegularExpression>
|
||||||
#include <QtGlobal>
|
#include <QtGlobal>
|
||||||
#if QT_VERSION > QT_VERSION_CHECK(5, 10, 0)
|
#if QT_VERSION > QT_VERSION_CHECK(5, 10, 0)
|
||||||
#include <QRandomGenerator>
|
#include <QRandomGenerator>
|
||||||
@ -62,25 +62,6 @@ class AOClient : public QObject {
|
|||||||
*/
|
*/
|
||||||
~AOClient();
|
~AOClient();
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Getter for the hardware ID.
|
|
||||||
*
|
|
||||||
* @return The hardware ID.
|
|
||||||
*
|
|
||||||
* @see #hwid
|
|
||||||
*/
|
|
||||||
QString getHwid();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Setter for the hardware ID.
|
|
||||||
*
|
|
||||||
* @param p_hwid A custom string to make into the hardware ID. The hardware ID *won't* become this string, it first
|
|
||||||
* goes through hashing.
|
|
||||||
*
|
|
||||||
* @see #hwid
|
|
||||||
*/
|
|
||||||
void setHwid(QString p_hwid);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Getter for the client's IPID.
|
* @brief Getter for the client's IPID.
|
||||||
*
|
*
|
||||||
@ -89,6 +70,7 @@ class AOClient : public QObject {
|
|||||||
* @see #ipid
|
* @see #ipid
|
||||||
*/
|
*/
|
||||||
QString getIpid();
|
QString getIpid();
|
||||||
|
void calculateIpid();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Getter for the pointer to the server.
|
* @brief Getter for the pointer to the server.
|
||||||
@ -164,6 +146,8 @@ class AOClient : public QObject {
|
|||||||
*/
|
*/
|
||||||
bool global_enabled = true;
|
bool global_enabled = true;
|
||||||
|
|
||||||
|
bool is_muted = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Represents the client's client software, and its version.
|
* @brief Represents the client's client software, and its version.
|
||||||
*
|
*
|
||||||
@ -186,18 +170,29 @@ class AOClient : public QObject {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The authorisation bitflag, representing what permissions a client can have.
|
* @brief The authorisation bitflag, representing what permissions a client can have.
|
||||||
|
*
|
||||||
|
* @showinitializer
|
||||||
*/
|
*/
|
||||||
QMap<QString, unsigned long long> ACLFlags {
|
QMap<QString, unsigned long long> ACLFlags {
|
||||||
{"KICK", 1ULL << 0},
|
{"NONE", 0ULL },
|
||||||
{"BAN", 1ULL << 1},
|
{"KICK", 1ULL << 0 },
|
||||||
{"BGLOCK", 1ULL << 2},
|
{"BAN", 1ULL << 1 },
|
||||||
{"MODIFY_USERS", 1ULL << 3},
|
{"BGLOCK", 1ULL << 2 },
|
||||||
{"CM", 1ULL << 4},
|
{"MODIFY_USERS", 1ULL << 3 },
|
||||||
{"GLOBAL_TIMER", 1ULL << 5},
|
{"CM", 1ULL << 4 },
|
||||||
{"CHANGE_EVI_MOD", 1ULL << 6},
|
{"GLOBAL_TIMER", 1ULL << 5 },
|
||||||
|
{"EVI_MOD", 1ULL << 6 },
|
||||||
|
{"MOTD", 1ULL << 7 },
|
||||||
|
{"ANNOUNCE", 1ULL << 8 },
|
||||||
|
{"MODCHAT", 1ULL << 9 },
|
||||||
|
{"MUTE", 1ULL << 10},
|
||||||
{"SUPER", ~0ULL },
|
{"SUPER", ~0ULL },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool is_shaken;
|
||||||
|
bool is_disemvoweled;
|
||||||
|
bool is_gimped;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
/**
|
/**
|
||||||
* @brief A slot for when the client disconnects from the server.
|
* @brief A slot for when the client disconnects from the server.
|
||||||
@ -607,6 +602,8 @@ class AOClient : public QObject {
|
|||||||
* @iscommand
|
* @iscommand
|
||||||
*/
|
*/
|
||||||
void cmdHelp(int argc, QStringList argv);
|
void cmdHelp(int argc, QStringList argv);
|
||||||
|
void cmdMOTD(int argc, QStringList argv);
|
||||||
|
void cmdAbout(int argc, QStringList argv);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @name Authentication
|
* @name Authentication
|
||||||
@ -652,6 +649,7 @@ class AOClient : public QObject {
|
|||||||
* @iscommand
|
* @iscommand
|
||||||
*/
|
*/
|
||||||
void cmdAddUser(int argc, QStringList argv);
|
void cmdAddUser(int argc, QStringList argv);
|
||||||
|
void cmdRemoveUser(int argc, QStringList argv);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Lists the permission of a given user.
|
* @brief Lists the permission of a given user.
|
||||||
@ -901,6 +899,7 @@ class AOClient : public QObject {
|
|||||||
* @iscommand
|
* @iscommand
|
||||||
*/
|
*/
|
||||||
void cmdBan(int argc, QStringList argv);
|
void cmdBan(int argc, QStringList argv);
|
||||||
|
void cmdUnBan(int argc, QStringList argv);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Kicks a client from the server, forcibly severing its connection to the server.
|
* @brief Kicks a client from the server, forcibly severing its connection to the server.
|
||||||
@ -914,6 +913,12 @@ class AOClient : public QObject {
|
|||||||
* @iscommand
|
* @iscommand
|
||||||
*/
|
*/
|
||||||
void cmdKick(int argc, QStringList argv);
|
void cmdKick(int argc, QStringList argv);
|
||||||
|
void cmdAnnounce(int argc, QStringList argv);
|
||||||
|
void cmdM(int argc, QStringList argv);
|
||||||
|
void cmdGM(int argc, QStringList argv);
|
||||||
|
void cmdMute(int argc, QStringList argv);
|
||||||
|
void cmdUnmute(int argc, QStringList argv);
|
||||||
|
void cmdBans(int argc, QStringList argv);
|
||||||
|
|
||||||
///@}
|
///@}
|
||||||
|
|
||||||
@ -1026,6 +1031,7 @@ class AOClient : public QObject {
|
|||||||
* @see AreaData::EvidenceMod
|
* @see AreaData::EvidenceMod
|
||||||
*/
|
*/
|
||||||
void cmdEvidenceMod(int argc, QStringList argv);
|
void cmdEvidenceMod(int argc, QStringList argv);
|
||||||
|
void cmdSubTheme(int argc, QStringList argv);
|
||||||
|
|
||||||
///@}
|
///@}
|
||||||
|
|
||||||
@ -1173,6 +1179,7 @@ class AOClient : public QObject {
|
|||||||
* @param Type The type of the dice-rolling being done.
|
* @param Type The type of the dice-rolling being done.
|
||||||
*/
|
*/
|
||||||
void diceThrower(int argc, QStringList argv, RollType Type);
|
void diceThrower(int argc, QStringList argv, RollType Type);
|
||||||
|
long long parseTime(QString input);
|
||||||
|
|
||||||
///@}
|
///@}
|
||||||
|
|
||||||
@ -1213,56 +1220,67 @@ class AOClient : public QObject {
|
|||||||
* See @ref CommandInfo "the type's documentation" for more details.
|
* See @ref CommandInfo "the type's documentation" for more details.
|
||||||
*/
|
*/
|
||||||
const QMap<QString, CommandInfo> commands {
|
const QMap<QString, CommandInfo> commands {
|
||||||
{"login", {ACLFlags.value("NONE"), 1, &AOClient::cmdLogin }},
|
{"login", {ACLFlags.value("NONE"), 1, &AOClient::cmdLogin}},
|
||||||
{"getareas", {ACLFlags.value("NONE"), 0, &AOClient::cmdGetAreas }},
|
{"getareas", {ACLFlags.value("NONE"), 0, &AOClient::cmdGetAreas}},
|
||||||
{"getarea", {ACLFlags.value("NONE"), 0, &AOClient::cmdGetArea }},
|
{"getarea", {ACLFlags.value("NONE"), 0, &AOClient::cmdGetArea}},
|
||||||
{"ban", {ACLFlags.value("BAN"), 2, &AOClient::cmdBan }},
|
{"ban", {ACLFlags.value("BAN"), 2, &AOClient::cmdBan}},
|
||||||
{"kick", {ACLFlags.value("KICK"), 2, &AOClient::cmdKick }},
|
{"kick", {ACLFlags.value("KICK"), 2, &AOClient::cmdKick}},
|
||||||
{"changeauth", {ACLFlags.value("SUPER"), 0, &AOClient::cmdChangeAuth }},
|
{"changeauth", {ACLFlags.value("SUPER"), 0, &AOClient::cmdChangeAuth}},
|
||||||
{"rootpass", {ACLFlags.value("SUPER"), 1, &AOClient::cmdSetRootPass }},
|
{"rootpass", {ACLFlags.value("SUPER"), 1, &AOClient::cmdSetRootPass}},
|
||||||
{"background", {ACLFlags.value("NONE"), 1, &AOClient::cmdSetBackground }},
|
{"background", {ACLFlags.value("NONE"), 1, &AOClient::cmdSetBackground}},
|
||||||
{"bg", {ACLFlags.value("NONE"), 1, &AOClient::cmdSetBackground }},
|
{"bg", {ACLFlags.value("NONE"), 1, &AOClient::cmdSetBackground}},
|
||||||
{"bglock", {ACLFlags.value("BGLOCK"), 0, &AOClient::cmdBgLock }},
|
{"bglock", {ACLFlags.value("BGLOCK"), 0, &AOClient::cmdBgLock}},
|
||||||
{"bgunlock", {ACLFlags.value("BGLOCK"), 0, &AOClient::cmdBgUnlock }},
|
{"bgunlock", {ACLFlags.value("BGLOCK"), 0, &AOClient::cmdBgUnlock}},
|
||||||
{"adduser", {ACLFlags.value("MODIFY_USERS"), 2, &AOClient::cmdAddUser }},
|
{"adduser", {ACLFlags.value("MODIFY_USERS"), 2, &AOClient::cmdAddUser}},
|
||||||
{"listperms", {ACLFlags.value("NONE"), 0, &AOClient::cmdListPerms }},
|
{"listperms", {ACLFlags.value("NONE"), 0, &AOClient::cmdListPerms}},
|
||||||
{"addperm", {ACLFlags.value("MODIFY_USERS"), 2, &AOClient::cmdAddPerms }},
|
{"addperm", {ACLFlags.value("MODIFY_USERS"), 2, &AOClient::cmdAddPerms}},
|
||||||
{"removeperm", {ACLFlags.value("MODIFY_USERS"), 2, &AOClient::cmdRemovePerms }},
|
{"removeperm", {ACLFlags.value("MODIFY_USERS"), 2, &AOClient::cmdRemovePerms}},
|
||||||
{"listusers", {ACLFlags.value("MODIFY_USERS"), 0, &AOClient::cmdListUsers }},
|
{"listusers", {ACLFlags.value("MODIFY_USERS"), 0, &AOClient::cmdListUsers}},
|
||||||
{"logout", {ACLFlags.value("NONE"), 0, &AOClient::cmdLogout }},
|
{"logout", {ACLFlags.value("NONE"), 0, &AOClient::cmdLogout}},
|
||||||
{"pos", {ACLFlags.value("NONE"), 1, &AOClient::cmdPos }},
|
{"pos", {ACLFlags.value("NONE"), 1, &AOClient::cmdPos}},
|
||||||
{"g", {ACLFlags.value("NONE"), 1, &AOClient::cmdG }},
|
{"g", {ACLFlags.value("NONE"), 1, &AOClient::cmdG}},
|
||||||
{"need", {ACLFlags.value("NONE"), 1, &AOClient::cmdNeed }},
|
{"need", {ACLFlags.value("NONE"), 1, &AOClient::cmdNeed}},
|
||||||
{"coinflip", {ACLFlags.value("NONE"), 0, &AOClient::cmdFlip }},
|
{"coinflip", {ACLFlags.value("NONE"), 0, &AOClient::cmdFlip}},
|
||||||
{"roll", {ACLFlags.value("NONE"), 0, &AOClient::cmdRoll }},
|
{"roll", {ACLFlags.value("NONE"), 0, &AOClient::cmdRoll}},
|
||||||
{"rollp", {ACLFlags.value("NONE"), 0, &AOClient::cmdRollP }},
|
{"rollp", {ACLFlags.value("NONE"), 0, &AOClient::cmdRollP}},
|
||||||
{"doc", {ACLFlags.value("NONE"), 0, &AOClient::cmdDoc }},
|
{"doc", {ACLFlags.value("NONE"), 0, &AOClient::cmdDoc}},
|
||||||
{"cleardoc", {ACLFlags.value("NONE"), 0, &AOClient::cmdClearDoc }},
|
{"cleardoc", {ACLFlags.value("NONE"), 0, &AOClient::cmdClearDoc}},
|
||||||
{"cm", {ACLFlags.value("NONE"), 0, &AOClient::cmdCM }},
|
{"cm", {ACLFlags.value("NONE"), 0, &AOClient::cmdCM}},
|
||||||
{"uncm", {ACLFlags.value("CM"), 0, &AOClient::cmdUnCM }},
|
{"uncm", {ACLFlags.value("CM"), 0, &AOClient::cmdUnCM}},
|
||||||
{"invite", {ACLFlags.value("CM"), 1, &AOClient::cmdInvite }},
|
{"invite", {ACLFlags.value("CM"), 1, &AOClient::cmdInvite}},
|
||||||
{"uninvite", {ACLFlags.value("CM"), 1, &AOClient::cmdUnInvite }},
|
{"uninvite", {ACLFlags.value("CM"), 1, &AOClient::cmdUnInvite}},
|
||||||
{"lock", {ACLFlags.value("CM"), 0, &AOClient::cmdLock }},
|
{"lock", {ACLFlags.value("CM"), 0, &AOClient::cmdLock}},
|
||||||
{"area_lock", {ACLFlags.value("CM"), 0, &AOClient::cmdLock }},
|
{"area_lock", {ACLFlags.value("CM"), 0, &AOClient::cmdLock}},
|
||||||
{"spectatable", {ACLFlags.value("CM"), 0, &AOClient::cmdSpectatable }},
|
{"spectatable", {ACLFlags.value("CM"), 0, &AOClient::cmdSpectatable}},
|
||||||
{"area_spectate", {ACLFlags.value("CM"), 0, &AOClient::cmdSpectatable }},
|
{"area_spectate", {ACLFlags.value("CM"), 0, &AOClient::cmdSpectatable}},
|
||||||
{"unlock", {ACLFlags.value("CM"), 0, &AOClient::cmdUnLock }},
|
{"unlock", {ACLFlags.value("CM"), 0, &AOClient::cmdUnLock}},
|
||||||
{"area_unlock", {ACLFlags.value("CM"), 0, &AOClient::cmdUnLock }},
|
{"area_unlock", {ACLFlags.value("CM"), 0, &AOClient::cmdUnLock}},
|
||||||
{"timer", {ACLFlags.value("CM"), 0, &AOClient::cmdTimer }},
|
{"timer", {ACLFlags.value("CM"), 0, &AOClient::cmdTimer}},
|
||||||
{"area", {ACLFlags.value("NONE"), 1, &AOClient::cmdArea }},
|
{"area", {ACLFlags.value("NONE"), 1, &AOClient::cmdArea}},
|
||||||
{"play", {ACLFlags.value("CM"), 1, &AOClient::cmdPlay }},
|
{"play", {ACLFlags.value("CM"), 1, &AOClient::cmdPlay}},
|
||||||
{"areakick", {ACLFlags.value("CM"), 1, &AOClient::cmdAreaKick }},
|
{"areakick", {ACLFlags.value("CM"), 1, &AOClient::cmdAreaKick}},
|
||||||
{"area_kick", {ACLFlags.value("CM"), 1, &AOClient::cmdAreaKick }},
|
{"area_kick", {ACLFlags.value("CM"), 1, &AOClient::cmdAreaKick}},
|
||||||
{"randomchar", {ACLFlags.value("NONE"), 0, &AOClient::cmdRandomChar }},
|
{"randomchar", {ACLFlags.value("NONE"), 0, &AOClient::cmdRandomChar}},
|
||||||
{"switch", {ACLFlags.value("NONE"), 1, &AOClient::cmdSwitch }},
|
{"switch", {ACLFlags.value("NONE"), 1, &AOClient::cmdSwitch}},
|
||||||
{"toggleglobal", {ACLFlags.value("NONE"), 0, &AOClient::cmdToggleGlobal }},
|
{"toggleglobal", {ACLFlags.value("NONE"), 0, &AOClient::cmdToggleGlobal}},
|
||||||
{"mods", {ACLFlags.value("NONE"), 0, &AOClient::cmdMods }},
|
{"mods", {ACLFlags.value("NONE"), 0, &AOClient::cmdMods}},
|
||||||
{"help", {ACLFlags.value("NONE"), 0, &AOClient::cmdHelp }},
|
{"help", {ACLFlags.value("NONE"), 0, &AOClient::cmdHelp}},
|
||||||
{"status", {ACLFlags.value("NONE"), 1, &AOClient::cmdStatus }},
|
{"status", {ACLFlags.value("NONE"), 1, &AOClient::cmdStatus}},
|
||||||
{"forcepos", {ACLFlags.value("CM"), 2, &AOClient::cmdForcePos }},
|
{"forcepos", {ACLFlags.value("CM"), 2, &AOClient::cmdForcePos}},
|
||||||
{"currentmusic", {ACLFlags.value("NONE"), 0, &AOClient::cmdCurrentMusic }},
|
{"currentmusic", {ACLFlags.value("NONE"), 0, &AOClient::cmdCurrentMusic}},
|
||||||
{"pm", {ACLFlags.value("NONE"), 2, &AOClient::cmdPM }},
|
{"pm", {ACLFlags.value("NONE"), 2, &AOClient::cmdPM}},
|
||||||
{"evidence_mod", {ACLFlags.value("CHANGE_EVI_MOD"), 1, &AOClient::cmdEvidenceMod }},
|
{"evidence_mod", {ACLFlags.value("EVI_MOD"), 1, &AOClient::cmdEvidenceMod}},
|
||||||
|
{"motd", {ACLFlags.value("NONE"), 0, &AOClient::cmdMOTD}},
|
||||||
|
{"announce", {ACLFlags.value("ANNOUNCE"), 1, &AOClient::cmdAnnounce}},
|
||||||
|
{"m", {ACLFlags.value("MODCHAT"), 1, &AOClient::cmdM}},
|
||||||
|
{"gm", {ACLFlags.value("MODCHAT"), 1, &AOClient::cmdGM}},
|
||||||
|
{"mute", {ACLFlags.value("MUTE"), 1, &AOClient::cmdMute}},
|
||||||
|
{"unmute", {ACLFlags.value("MUTE"), 1, &AOClient::cmdUnmute}},
|
||||||
|
{"bans", {ACLFlags.value("BAN"), 0, &AOClient::cmdBans}},
|
||||||
|
{"unban", {ACLFlags.value("BAN"), 1, &AOClient::cmdUnBan}},
|
||||||
|
{"removeuser", {ACLFlags.value("MODIFY_USERS"), 1, &AOClient::cmdRemoveUser}},
|
||||||
|
{"subtheme", {ACLFlags.value("CM"), 1, &AOClient::cmdSubTheme}},
|
||||||
|
{"about", {ACLFlags.value("NONE"), 0, &AOClient::cmdAbout}},
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -35,15 +35,7 @@ class Logger;
|
|||||||
class AreaData : public QObject {
|
class AreaData : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
AreaData(QString p_name, int p_index);
|
||||||
/**
|
|
||||||
* @brief Creates an area.
|
|
||||||
*
|
|
||||||
* @param p_characters A list of characters that may be selected in the area.
|
|
||||||
* @param p_name The name of the area.
|
|
||||||
* @param p_index The index of the area.
|
|
||||||
*/
|
|
||||||
AreaData(QStringList p_characters, QString p_name, int p_index);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The data for evidence in the area.
|
* @brief The data for evidence in the area.
|
||||||
@ -69,14 +61,7 @@ class AreaData : public QObject {
|
|||||||
*/
|
*/
|
||||||
int index;
|
int index;
|
||||||
|
|
||||||
/**
|
QList<int> characters_taken;
|
||||||
* @brief A map of characters' names and whether they are taken or not.
|
|
||||||
*
|
|
||||||
* @details The key for the map the given characters' internal names (i.e., the name of their directory
|
|
||||||
* in `base/characters/` clientside), while the values are true if they are already taken in the area,
|
|
||||||
* false if not.
|
|
||||||
*/
|
|
||||||
QMap<QString, bool> characters_taken;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A list of Evidence currently available in the area's court record.
|
* @brief A list of Evidence currently available in the area's court record.
|
||||||
|
@ -62,9 +62,9 @@ class ConfigManager {
|
|||||||
*/
|
*/
|
||||||
struct server_settings {
|
struct server_settings {
|
||||||
QString ms_ip; //!< The IP address of the master server to establish connection to.
|
QString ms_ip; //!< The IP address of the master server to establish connection to.
|
||||||
int port; //!< The port of the master server to establish connection to.
|
int port; //!< The TCP port the server will accept client connections through.
|
||||||
int ws_port; //!< The WebSocket port the server will accept client connections through.
|
int ws_port; //!< The WebSocket port the server will accept client connections through.
|
||||||
int local_port; //!< The TCP port the server will accept client connections through.
|
int ms_port; //!< The port of the master server to establish connection to.
|
||||||
QString name; //!< The name of the server as advertised on the server browser.
|
QString name; //!< The name of the server as advertised on the server browser.
|
||||||
QString description; //!< The description of the server as advertised on the server browser.
|
QString description; //!< The description of the server as advertised on the server browser.
|
||||||
bool advertise_server; //!< The server will only be announced to the master server (and thus appear on the master server list) if this is true.
|
bool advertise_server; //!< The server will only be announced to the master server (and thus appear on the master server list) if this is true.
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#define BAN_MANAGER_H
|
#define BAN_MANAGER_H
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <QDateTime>
|
||||||
#include <QHostAddress>
|
#include <QHostAddress>
|
||||||
#include <QMessageAuthenticationCode>
|
#include <QMessageAuthenticationCode>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
@ -89,18 +90,23 @@ public:
|
|||||||
* or `"Ban reason not found."` if the hardware ID is not actually banned.
|
* or `"Ban reason not found."` if the hardware ID is not actually banned.
|
||||||
*/
|
*/
|
||||||
QString getBanReason(QString hdid);
|
QString getBanReason(QString hdid);
|
||||||
|
long long getBanDuration(QString hdid);
|
||||||
|
long long getBanDuration(QHostAddress ip);
|
||||||
|
int getBanID(QString hdid);
|
||||||
|
int getBanID(QHostAddress ip);
|
||||||
|
|
||||||
/**
|
struct BanInfo {
|
||||||
* @brief Records a ban for the give IPID-IP address-hardware ID combination.
|
QString ipid;
|
||||||
*
|
QHostAddress ip;
|
||||||
* @param ipid The IPID to ban.
|
QString hdid;
|
||||||
* @param ip The IP address to ban. The source should be the same as with the IPID
|
unsigned long time;
|
||||||
* (i.e., they should point to the same user).
|
QString reason;
|
||||||
* @param hdid The hardware ID to ban. Once again, should point to the same user as the IPID and the IP address.
|
long long duration;
|
||||||
* @param time The number of seconds to ban the target for.
|
};
|
||||||
* @param reason The reason the target was banned.
|
QList<BanInfo> getRecentBans();
|
||||||
*/
|
|
||||||
void addBan(QString ipid, QHostAddress ip, QString hdid, unsigned long time, QString reason);
|
void addBan(BanInfo ban);
|
||||||
|
bool invalidateBan(int id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Creates an authorised user.
|
* @brief Creates an authorised user.
|
||||||
@ -116,6 +122,7 @@ public:
|
|||||||
* @see AOClient::ACLFlags for the potential special permissions a user may have.
|
* @see AOClient::ACLFlags for the potential special permissions a user may have.
|
||||||
*/
|
*/
|
||||||
bool createUser(QString username, QString salt, QString password, unsigned long long acl);
|
bool createUser(QString username, QString salt, QString password, unsigned long long acl);
|
||||||
|
bool deleteUser(QString username);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Gets the permissions of a given user.
|
* @brief Gets the permissions of a given user.
|
||||||
|
@ -80,6 +80,8 @@ class Server : public QObject {
|
|||||||
*/
|
*/
|
||||||
AOClient* getClient(QString ipid);
|
AOClient* getClient(QString ipid);
|
||||||
|
|
||||||
|
QList<AOClient*> getClientsByIpid(QString ipid);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Gets a pointer to a client by user ID.
|
* @brief Gets a pointer to a client by user ID.
|
||||||
*
|
*
|
||||||
@ -194,6 +196,7 @@ class Server : public QObject {
|
|||||||
* @note Unused. getServerName() serves its purpose instead.
|
* @note Unused. getServerName() serves its purpose instead.
|
||||||
*/
|
*/
|
||||||
QString server_name;
|
QString server_name;
|
||||||
|
QString MOTD;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The server-wide global timer.
|
* @brief The server-wide global timer.
|
||||||
|
@ -49,7 +49,7 @@ void Advertiser::socketConnected()
|
|||||||
|
|
||||||
AOPacket ao_packet("SCC",
|
AOPacket ao_packet("SCC",
|
||||||
{concat_ports, name, description,
|
{concat_ports, name, description,
|
||||||
"akashi v" + QCoreApplication::applicationVersion()});
|
"akashi " + QCoreApplication::applicationVersion()});
|
||||||
QByteArray data = ao_packet.toUtf8();
|
QByteArray data = ao_packet.toUtf8();
|
||||||
|
|
||||||
socket->write(data);
|
socket->write(data);
|
||||||
|
@ -48,14 +48,20 @@ void AOClient::clientDisconnected()
|
|||||||
arup(ARUPType::PLAYER_COUNT, true);
|
arup(ARUPType::PLAYER_COUNT, true);
|
||||||
}
|
}
|
||||||
if (current_char != "") {
|
if (current_char != "") {
|
||||||
server->areas[current_area]->characters_taken[current_char] =
|
server->areas[current_area]->characters_taken.removeAll(server->getCharID(current_char));
|
||||||
false;
|
|
||||||
server->updateCharsTaken(server->areas[current_area]);
|
server->updateCharsTaken(server->areas[current_area]);
|
||||||
}
|
}
|
||||||
|
bool update_locks;
|
||||||
for (AreaData* area : server->areas) {
|
for (AreaData* area : server->areas) {
|
||||||
area->owners.removeAll(id);
|
area->owners.removeAll(id);
|
||||||
area->invited.removeAll(id);
|
area->invited.removeAll(id);
|
||||||
|
if (area->owners.isEmpty() && area->locked != AreaData::FREE) {
|
||||||
|
area->locked = AreaData::FREE;
|
||||||
|
update_locks = true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (update_locks)
|
||||||
|
arup(ARUPType::LOCKED, true);
|
||||||
arup(ARUPType::CM, true);
|
arup(ARUPType::CM, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,8 +99,7 @@ void AOClient::changeArea(int new_area)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (current_char != "") {
|
if (current_char != "") {
|
||||||
server->areas[current_area]->characters_taken[current_char] =
|
server->areas[current_area]->characters_taken.removeAll(server->getCharID(current_char));
|
||||||
false;
|
|
||||||
server->updateCharsTaken(server->areas[current_area]);
|
server->updateCharsTaken(server->areas[current_area]);
|
||||||
}
|
}
|
||||||
server->areas[new_area]->player_count++;
|
server->areas[new_area]->player_count++;
|
||||||
@ -105,23 +110,23 @@ void AOClient::changeArea(int new_area)
|
|||||||
sendPacket("HP", {"1", QString::number(server->areas[new_area]->def_hp)});
|
sendPacket("HP", {"1", QString::number(server->areas[new_area]->def_hp)});
|
||||||
sendPacket("HP", {"2", QString::number(server->areas[new_area]->pro_hp)});
|
sendPacket("HP", {"2", QString::number(server->areas[new_area]->pro_hp)});
|
||||||
sendPacket("BN", {server->areas[new_area]->background});
|
sendPacket("BN", {server->areas[new_area]->background});
|
||||||
if (server->areas[current_area]->characters_taken[current_char]) {
|
if (server->areas[current_area]->characters_taken.contains(server->getCharID(current_char))) {
|
||||||
server->updateCharsTaken(server->areas[current_area]);
|
server->updateCharsTaken(server->areas[current_area]);
|
||||||
current_char = "";
|
current_char = "";
|
||||||
sendPacket("DONE");
|
sendPacket("DONE");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
server->areas[current_area]->characters_taken[current_char] = true;
|
server->areas[current_area]->characters_taken.append(server->getCharID(current_char));
|
||||||
server->updateCharsTaken(server->areas[current_area]);
|
server->updateCharsTaken(server->areas[current_area]);
|
||||||
}
|
}
|
||||||
for (QTimer* timer : server->areas[current_area]->timers) {
|
for (QTimer* timer : server->areas[current_area]->timers) {
|
||||||
int timer_id = server->areas[current_area]->timers.indexOf(timer) + 1;
|
int timer_id = server->areas[current_area]->timers.indexOf(timer) + 1;
|
||||||
if (timer->isActive()) {
|
if (timer->isActive()) {
|
||||||
sendPacket("TI", {QString::number(timer_id), QString::number(2)});
|
sendPacket("TI", {QString::number(timer_id), "2"});
|
||||||
sendPacket("TI", {QString::number(timer_id), QString::number(0), QString::number(QTime(0,0).msecsTo(QTime(0,0).addMSecs(timer->remainingTime())))});
|
sendPacket("TI", {QString::number(timer_id), "0", QString::number(QTime(0,0).msecsTo(QTime(0,0).addMSecs(timer->remainingTime())))});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
sendPacket("TI", {QString::number(timer_id), QString::number(3)});
|
sendPacket("TI", {QString::number(timer_id), "3"});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sendServerMessage("You moved to area " + server->area_names[current_area]);
|
sendServerMessage("You moved to area " + server->area_names[current_area]);
|
||||||
@ -134,7 +139,7 @@ void AOClient::changeCharacter(int char_id)
|
|||||||
AreaData* area = server->areas[current_area];
|
AreaData* area = server->areas[current_area];
|
||||||
|
|
||||||
if (current_char != "") {
|
if (current_char != "") {
|
||||||
area->characters_taken[current_char] = false;
|
area->characters_taken.removeAll(server->getCharID(current_char));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(char_id > server->characters.length())
|
if(char_id > server->characters.length())
|
||||||
@ -142,11 +147,11 @@ void AOClient::changeCharacter(int char_id)
|
|||||||
|
|
||||||
if (char_id >= 0) {
|
if (char_id >= 0) {
|
||||||
QString char_selected = server->characters[char_id];
|
QString char_selected = server->characters[char_id];
|
||||||
bool taken = area->characters_taken.value(char_selected);
|
bool taken = area->characters_taken.contains(char_id);
|
||||||
if (taken || char_selected == "")
|
if (taken || char_selected == "")
|
||||||
return;
|
return;
|
||||||
|
|
||||||
area->characters_taken[char_selected] = true;
|
area->characters_taken.append(char_id);
|
||||||
current_char = char_selected;
|
current_char = char_selected;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -157,24 +162,6 @@ void AOClient::changeCharacter(int char_id)
|
|||||||
|
|
||||||
server->updateCharsTaken(area);
|
server->updateCharsTaken(area);
|
||||||
sendPacket("PV", {QString::number(id), "CID", QString::number(char_id)});
|
sendPacket("PV", {QString::number(id), "CID", QString::number(char_id)});
|
||||||
fullArup();
|
|
||||||
if (server->timer->isActive()) {
|
|
||||||
sendPacket("TI", {QString::number(0), QString::number(2)});
|
|
||||||
sendPacket("TI", {QString::number(0), QString::number(0), QString::number(QTime(0,0).msecsTo(QTime(0,0).addMSecs(server->timer->remainingTime())))});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
sendPacket("TI", {QString::number(0), QString::number(3)});
|
|
||||||
}
|
|
||||||
for (QTimer* timer : area->timers) {
|
|
||||||
int timer_id = area->timers.indexOf(timer) + 1;
|
|
||||||
if (timer->isActive()) {
|
|
||||||
sendPacket("TI", {QString::number(timer_id), QString::number(2)});
|
|
||||||
sendPacket("TI", {QString::number(timer_id), QString::number(0), QString::number(QTime(0,0).msecsTo(QTime(0,0).addMSecs(timer->remainingTime())))});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
sendPacket("TI", {QString::number(timer_id), QString::number(3)});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AOClient::changePosition(QString new_pos)
|
void AOClient::changePosition(QString new_pos)
|
||||||
@ -271,22 +258,17 @@ void AOClient::sendPacket(QString header)
|
|||||||
sendPacket(AOPacket(header, {}));
|
sendPacket(AOPacket(header, {}));
|
||||||
}
|
}
|
||||||
|
|
||||||
QString AOClient::getHwid() { return hwid; }
|
void AOClient::calculateIpid()
|
||||||
|
|
||||||
void AOClient::setHwid(QString p_hwid)
|
|
||||||
{
|
{
|
||||||
// TODO: add support for longer hwids?
|
// TODO: add support for longer ipids?
|
||||||
// This reduces the (fairly high) chance of
|
// This reduces the (fairly high) chance of
|
||||||
// birthday paradox issues arising. However,
|
// birthday paradox issues arising. However,
|
||||||
// typing more than 8 characters might be a
|
// typing more than 8 characters might be a
|
||||||
// bit cumbersome.
|
// bit cumbersome.
|
||||||
hwid = p_hwid;
|
|
||||||
|
|
||||||
QCryptographicHash hash(
|
QCryptographicHash hash(QCryptographicHash::Md5); // Don't need security, just hashing for uniqueness
|
||||||
QCryptographicHash::Md5); // Don't need security, just
|
|
||||||
// hashing for uniqueness
|
hash.addData(remote_ip.toString().toUtf8());
|
||||||
QString concat_ip_id = remote_ip.toString() + p_hwid;
|
|
||||||
hash.addData(concat_ip_id.toUtf8());
|
|
||||||
|
|
||||||
ipid = hash.result().toHex().right(8); // Use the last 8 characters (4 bytes)
|
ipid = hash.result().toHex().right(8); // Use the last 8 characters (4 bytes)
|
||||||
}
|
}
|
||||||
|
@ -17,8 +17,7 @@
|
|||||||
//////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////
|
||||||
#include "include/area_data.h"
|
#include "include/area_data.h"
|
||||||
|
|
||||||
AreaData::AreaData(QStringList characters, QString p_name, int p_index) :
|
AreaData::AreaData(QString p_name, int p_index) :
|
||||||
name(p_name),
|
|
||||||
index(p_index),
|
index(p_index),
|
||||||
player_count(0),
|
player_count(0),
|
||||||
status(IDLE),
|
status(IDLE),
|
||||||
@ -27,9 +26,9 @@ AreaData::AreaData(QStringList characters, QString p_name, int p_index) :
|
|||||||
def_hp(10),
|
def_hp(10),
|
||||||
pro_hp(10)
|
pro_hp(10)
|
||||||
{
|
{
|
||||||
for (QString cur_char : characters) {
|
QStringList name_split = p_name.split(":");
|
||||||
characters_taken.insert(cur_char, false);
|
name_split.removeFirst();
|
||||||
}
|
name = name_split.join(":");
|
||||||
QSettings areas_ini("config/areas.ini", QSettings::IniFormat);
|
QSettings areas_ini("config/areas.ini", QSettings::IniFormat);
|
||||||
areas_ini.beginGroup(p_name);
|
areas_ini.beginGroup(p_name);
|
||||||
background = areas_ini.value("background", "gs4").toString();
|
background = areas_ini.value("background", "gs4").toString();
|
||||||
|
295
src/commands.cpp
295
src/commands.cpp
@ -42,10 +42,12 @@ void AOClient::cmdLogin(int argc, QStringList argv)
|
|||||||
sendServerMessage("No modpass is set! Please set a modpass before authenticating.");
|
sendServerMessage("No modpass is set! Please set a modpass before authenticating.");
|
||||||
}
|
}
|
||||||
else if(argv[0] == modpass) {
|
else if(argv[0] == modpass) {
|
||||||
sendServerMessage("Logged in as a moderator."); // This string has to be exactly this, because it is hardcoded in the client
|
sendPacket("AUTH", {"1"}); // Client: "You were granted the Disable Modcalls button."
|
||||||
|
sendServerMessage("Logged in as a moderator."); // pre-2.9.1 clients are hardcoded to display the mod UI when this string is sent in OOC
|
||||||
authenticated = true;
|
authenticated = true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
sendPacket("AUTH", {"0"}); // Client: "Login unsuccessful."
|
||||||
sendServerMessage("Incorrect password.");
|
sendServerMessage("Incorrect password.");
|
||||||
}
|
}
|
||||||
server->areas.value(current_area)->logger->logLogin(this, authenticated, "moderator");
|
server->areas.value(current_area)->logger->logLogin(this, authenticated, "moderator");
|
||||||
@ -60,10 +62,13 @@ void AOClient::cmdLogin(int argc, QStringList argv)
|
|||||||
if (server->db_manager->authenticate(username, password)) {
|
if (server->db_manager->authenticate(username, password)) {
|
||||||
moderator_name = username;
|
moderator_name = username;
|
||||||
authenticated = true;
|
authenticated = true;
|
||||||
sendServerMessage("Logged in as a moderator.");
|
sendPacket("AUTH", {"1"}); // Client: "You were granted the Disable Modcalls button."
|
||||||
|
if (version.release <= 2 && version.major <= 9 && version.minor <= 0)
|
||||||
|
sendServerMessage("Logged in as a moderator."); // pre-2.9.1 clients are hardcoded to display the mod UI when this string is sent in OOC
|
||||||
sendServerMessage("Welcome, " + username);
|
sendServerMessage("Welcome, " + username);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
sendPacket("AUTH", {"0"}); // Client: "Login unsuccessful."
|
||||||
sendServerMessage("Incorrect password.");
|
sendServerMessage("Incorrect password.");
|
||||||
}
|
}
|
||||||
server->areas.value(current_area)->logger->logLogin(this, authenticated, username);
|
server->areas.value(current_area)->logger->logLogin(this, authenticated, username);
|
||||||
@ -89,33 +94,72 @@ void AOClient::cmdGetArea(int argc, QStringList argv)
|
|||||||
|
|
||||||
void AOClient::cmdBan(int argc, QStringList argv)
|
void AOClient::cmdBan(int argc, QStringList argv)
|
||||||
{
|
{
|
||||||
QString target_ipid = argv[0];
|
QString args_str = argv[1];
|
||||||
QHostAddress ip;
|
if (argc > 2) {
|
||||||
QString hdid;
|
for (int i = 2; i < argc; i++)
|
||||||
unsigned long time = QDateTime::currentDateTime().toTime_t();
|
args_str += " " + argv[i];
|
||||||
QString reason = argv[1];
|
}
|
||||||
|
|
||||||
|
DBManager::BanInfo ban;
|
||||||
|
|
||||||
|
QRegularExpression quoteMatcher("['\"](.+?)[\"']");
|
||||||
|
QRegularExpressionMatchIterator matches = quoteMatcher.globalMatch(args_str);
|
||||||
|
QList<QString> unquoted_args;
|
||||||
|
while (matches.hasNext()) {
|
||||||
|
QRegularExpressionMatch match = matches.next();
|
||||||
|
unquoted_args.append(match.captured(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
QString duration = "perma";
|
||||||
|
|
||||||
|
if (unquoted_args.length() < 1) {
|
||||||
|
sendServerMessage("Invalid syntax. Usage:\n/ban <ipid> \"<reason>\" \"<duration>\"");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ban.reason = unquoted_args.at(0);
|
||||||
|
if (unquoted_args.length() > 1)
|
||||||
|
duration = unquoted_args.at(1);
|
||||||
|
|
||||||
|
long long duration_seconds = 0;
|
||||||
|
if (duration == "perma")
|
||||||
|
duration_seconds = -2;
|
||||||
|
else
|
||||||
|
duration_seconds = parseTime(duration);
|
||||||
|
|
||||||
|
if (duration_seconds == -1) {
|
||||||
|
sendServerMessage("Invalid time format. Format example: 1h30m");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ban.duration = duration_seconds;
|
||||||
|
|
||||||
|
ban.ipid = argv[0];
|
||||||
|
ban.time = QDateTime::currentDateTime().toSecsSinceEpoch();
|
||||||
bool ban_logged = false;
|
bool ban_logged = false;
|
||||||
|
int kick_counter = 0;
|
||||||
|
|
||||||
if (argc > 2) {
|
if (argc > 2) {
|
||||||
for (int i = 2; i < argv.length(); i++) {
|
for (int i = 2; i < argv.length(); i++) {
|
||||||
reason += " " + argv[i];
|
ban.reason += " " + argv[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (AOClient* client : server->clients) {
|
for (AOClient* client : server->getClientsByIpid(ban.ipid)) {
|
||||||
if (client->getIpid() == target_ipid) {
|
|
||||||
if (!ban_logged) {
|
if (!ban_logged) {
|
||||||
ip = client->remote_ip;
|
ban.ip = client->remote_ip;
|
||||||
hdid = client->hwid;
|
ban.hdid = client->hwid;
|
||||||
server->db_manager->addBan(target_ipid, ip, hdid, time, reason);
|
server->db_manager->addBan(ban);
|
||||||
sendServerMessage("Banned user with ipid " + target_ipid + " for reason: " + reason);
|
sendServerMessage("Banned user with ipid " + ban.ipid + " for reason: " + ban.reason);
|
||||||
ban_logged = true;
|
ban_logged = true;
|
||||||
}
|
}
|
||||||
client->sendPacket("KB", {reason});
|
client->sendPacket("KB", {ban.reason + "\nID: " + QString::number(server->db_manager->getBanID(ban.ip)) + "\nUntil: " + QDateTime::fromSecsSinceEpoch(ban.time).addSecs(ban.duration).toString("dd.MM.yyyy, hh:mm")});
|
||||||
client->socket->close();
|
client->socket->close();
|
||||||
}
|
kick_counter++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (kick_counter > 1)
|
||||||
|
sendServerMessage("Kicked " + QString::number(kick_counter) + " clients with matching ipids.");
|
||||||
if (!ban_logged)
|
if (!ban_logged)
|
||||||
sendServerMessage("User with ipid not found!");
|
sendServerMessage("User with ipid not found!");
|
||||||
}
|
}
|
||||||
@ -124,7 +168,7 @@ void AOClient::cmdKick(int argc, QStringList argv)
|
|||||||
{
|
{
|
||||||
QString target_ipid = argv[0];
|
QString target_ipid = argv[0];
|
||||||
QString reason = argv[1];
|
QString reason = argv[1];
|
||||||
bool did_kick = false;
|
int kick_counter = 0;
|
||||||
|
|
||||||
if (argc > 2) {
|
if (argc > 2) {
|
||||||
for (int i = 2; i < argv.length(); i++) {
|
for (int i = 2; i < argv.length(); i++) {
|
||||||
@ -132,16 +176,14 @@ void AOClient::cmdKick(int argc, QStringList argv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (AOClient* client : server->clients) {
|
for (AOClient* client : server->getClientsByIpid(target_ipid)) {
|
||||||
if (client->getIpid() == target_ipid) {
|
|
||||||
client->sendPacket("KK", {reason});
|
client->sendPacket("KK", {reason});
|
||||||
client->socket->close();
|
client->socket->close();
|
||||||
did_kick = true;
|
kick_counter++;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (did_kick)
|
if (kick_counter > 0)
|
||||||
sendServerMessage("Kicked user with ipid " + target_ipid + " for reason: " + reason);
|
sendServerMessage("Kicked " + QString::number(kick_counter) + " client(s) with ipid " + target_ipid + " for reason: " + reason);
|
||||||
else
|
else
|
||||||
sendServerMessage("User with ipid not found!");
|
sendServerMessage("User with ipid not found!");
|
||||||
}
|
}
|
||||||
@ -232,6 +274,14 @@ void AOClient::cmdAddUser(int argc, QStringList argv)
|
|||||||
sendServerMessage("Unable to create user " + argv[0] + ".\nDoes a user with that name already exist?");
|
sendServerMessage("Unable to create user " + argv[0] + ".\nDoes a user with that name already exist?");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AOClient::cmdRemoveUser(int argc, QStringList argv)
|
||||||
|
{
|
||||||
|
if (server->db_manager->deleteUser(argv[0]))
|
||||||
|
sendServerMessage("Successfully removed user " + argv[0] + ".");
|
||||||
|
else
|
||||||
|
sendServerMessage("Unable to remove user " + argv[0] + ".\nDoes it exist?");
|
||||||
|
}
|
||||||
|
|
||||||
void AOClient::cmdListPerms(int argc, QStringList argv)
|
void AOClient::cmdListPerms(int argc, QStringList argv)
|
||||||
{
|
{
|
||||||
unsigned long long user_acl = server->db_manager->getACL(moderator_name);
|
unsigned long long user_acl = server->db_manager->getACL(moderator_name);
|
||||||
@ -359,7 +409,7 @@ void AOClient::cmdLogout(int argc, QStringList argv)
|
|||||||
}
|
}
|
||||||
authenticated = false;
|
authenticated = false;
|
||||||
moderator_name = "";
|
moderator_name = "";
|
||||||
sendServerMessage("You have been logged out.");
|
sendPacket("AUTH", {"-1"}); // Client: "You were logged out."
|
||||||
}
|
}
|
||||||
|
|
||||||
void AOClient::cmdPos(int argc, QStringList argv)
|
void AOClient::cmdPos(int argc, QStringList argv)
|
||||||
@ -505,8 +555,13 @@ void AOClient::cmdUnCM(int argc, QStringList argv)
|
|||||||
area->invited.removeAll(id);
|
area->invited.removeAll(id);
|
||||||
sendServerMessage("You are no longer CM in this area.");
|
sendServerMessage("You are no longer CM in this area.");
|
||||||
arup(ARUPType::CM, true);
|
arup(ARUPType::CM, true);
|
||||||
if (area->owners.isEmpty())
|
if (area->owners.isEmpty()) {
|
||||||
area->invited.clear();
|
area->invited.clear();
|
||||||
|
if (area->locked != AreaData::FREE) {
|
||||||
|
area->locked = AreaData::FREE;
|
||||||
|
arup(ARUPType::LOCKED, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AOClient::cmdInvite(int argc, QStringList argv)
|
void AOClient::cmdInvite(int argc, QStringList argv)
|
||||||
@ -657,28 +712,28 @@ void AOClient::cmdTimer(int argc, QStringList argv)
|
|||||||
requested_timer->setInterval(QTime(0,0).msecsTo(requested_time));
|
requested_timer->setInterval(QTime(0,0).msecsTo(requested_time));
|
||||||
requested_timer->start();
|
requested_timer->start();
|
||||||
sendServerMessage("Set timer " + QString::number(timer_id) + " to " + argv[1] + ".");
|
sendServerMessage("Set timer " + QString::number(timer_id) + " to " + argv[1] + ".");
|
||||||
sendPacket("TI", {QString::number(timer_id), QString::number(2)});
|
sendPacket("TI", {QString::number(timer_id), "2"}); // Show the timer
|
||||||
sendPacket("TI", {QString::number(timer_id), QString::number(0), QString::number(QTime(0,0).msecsTo(requested_time))});
|
sendPacket("TI", {QString::number(timer_id), "0", QString::number(QTime(0,0).msecsTo(requested_time))});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (argv[1] == "start") {
|
if (argv[1] == "start") {
|
||||||
requested_timer->start();
|
requested_timer->start();
|
||||||
sendServerMessage("Started timer " + QString::number(timer_id) + ".");
|
sendServerMessage("Started timer " + QString::number(timer_id) + ".");
|
||||||
sendPacket("TI", {QString::number(timer_id), QString::number(2)});
|
sendPacket("TI", {QString::number(timer_id), "2"}); // Show the timer
|
||||||
sendPacket("TI", {QString::number(timer_id), QString::number(0), QString::number(QTime(0,0).msecsTo(QTime(0,0).addMSecs(requested_timer->remainingTime())))});
|
sendPacket("TI", {QString::number(timer_id), "0", QString::number(QTime(0,0).msecsTo(QTime(0,0).addMSecs(requested_timer->remainingTime())))});
|
||||||
}
|
}
|
||||||
else if (argv[1] == "pause" || argv[1] == "stop") {
|
else if (argv[1] == "pause" || argv[1] == "stop") {
|
||||||
requested_timer->setInterval(requested_timer->remainingTime());
|
requested_timer->setInterval(requested_timer->remainingTime());
|
||||||
requested_timer->stop();
|
requested_timer->stop();
|
||||||
sendServerMessage("Stopped timer " + QString::number(timer_id) + ".");
|
sendServerMessage("Stopped timer " + QString::number(timer_id) + ".");
|
||||||
sendPacket("TI", {QString::number(timer_id), QString::number(1), QString::number(QTime(0,0).msecsTo(QTime(0,0).addMSecs(requested_timer->interval())))});
|
sendPacket("TI", {QString::number(timer_id), "1", QString::number(QTime(0,0).msecsTo(QTime(0,0).addMSecs(requested_timer->interval())))});
|
||||||
}
|
}
|
||||||
else if (argv[1] == "hide" || argv[1] == "unset") {
|
else if (argv[1] == "hide" || argv[1] == "unset") {
|
||||||
requested_timer->setInterval(0);
|
requested_timer->setInterval(0);
|
||||||
requested_timer->stop();
|
requested_timer->stop();
|
||||||
sendServerMessage("Hid timer " + QString::number(timer_id) + ".");
|
sendServerMessage("Hid timer " + QString::number(timer_id) + ".");
|
||||||
sendPacket("TI", {QString::number(timer_id), QString::number(3)});
|
sendPacket("TI", {QString::number(timer_id), "3"}); // Hide the timer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -722,7 +777,8 @@ void AOClient::cmdPlay(int argc, QStringList argv)
|
|||||||
QString song = argv.join(" ");
|
QString song = argv.join(" ");
|
||||||
area->current_music = song;
|
area->current_music = song;
|
||||||
area->music_played_by = showname;
|
area->music_played_by = showname;
|
||||||
sendPacket("MC", {song, QString::number(server->getCharID(current_char)), showname, "1", "0"});
|
AOPacket music_change("MC", {song, QString::number(server->getCharID(current_char)), showname, "1", "0"});
|
||||||
|
server->broadcast(music_change, current_area);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AOClient::cmdAreaKick(int argc, QStringList argv)
|
void AOClient::cmdAreaKick(int argc, QStringList argv)
|
||||||
@ -776,8 +832,8 @@ void AOClient::cmdMods(int argc, QStringList argv)
|
|||||||
if (client->authenticated) {
|
if (client->authenticated) {
|
||||||
entries << "---";
|
entries << "---";
|
||||||
if (auth_type != "simple")
|
if (auth_type != "simple")
|
||||||
entries << "Moderator: " + moderator_name;
|
entries << "Moderator: " + client->moderator_name;
|
||||||
entries << "OOC name: " + ooc_name;
|
entries << "OOC name: " + client->ooc_name;
|
||||||
entries << "ID: " + QString::number(client->id);
|
entries << "ID: " + QString::number(client->id);
|
||||||
entries << "Area: " + QString::number(client->current_area);
|
entries << "Area: " + QString::number(client->current_area);
|
||||||
entries << "Character: " + client->current_char;
|
entries << "Character: " + client->current_char;
|
||||||
@ -852,6 +908,133 @@ void AOClient::cmdPM(int arc, QStringList argv)
|
|||||||
target_client->sendServerMessage("Message from " + ooc_name + " (" + QString::number(id) + "): " + message);
|
target_client->sendServerMessage("Message from " + ooc_name + " (" + QString::number(id) + "): " + message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AOClient::cmdMOTD(int argc, QStringList argv)
|
||||||
|
{
|
||||||
|
if (argc == 0) {
|
||||||
|
sendServerMessage("=== MOTD ===\r\n" + server->MOTD + "\r\n=============");
|
||||||
|
}
|
||||||
|
else if (argc > 0) {
|
||||||
|
if (checkAuth(ACLFlags.value("MOTD"))) {
|
||||||
|
QString MOTD = argv.join(" ");
|
||||||
|
server->MOTD = MOTD;
|
||||||
|
sendServerMessage("MOTD has been changed.");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sendServerMessage("You do not have permission to change the MOTD");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AOClient::cmdAnnounce(int argc, QStringList argv)
|
||||||
|
{
|
||||||
|
sendServerBroadcast("=== Announcement ===\r\n" + argv.join(" ") + "\r\n=============");
|
||||||
|
}
|
||||||
|
|
||||||
|
void AOClient::cmdM(int argc, QStringList argv)
|
||||||
|
{
|
||||||
|
QString sender_name = ooc_name;
|
||||||
|
QString sender_message = argv.join(" ");
|
||||||
|
for (AOClient* client : server->clients) {
|
||||||
|
if (client->checkAuth(ACLFlags.value("MODCHAT")))
|
||||||
|
client->sendPacket("CT", {"[M]" + sender_name, sender_message});
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AOClient::cmdGM(int argc, QStringList argv)
|
||||||
|
{
|
||||||
|
QString sender_name = ooc_name;
|
||||||
|
QString sender_area = server->area_names.value(current_area);
|
||||||
|
QString sender_message = argv.join(" ");
|
||||||
|
for (AOClient* client : server->clients) {
|
||||||
|
if (client->global_enabled) {
|
||||||
|
client->sendPacket("CT", {"[G][" + sender_area + "]" + "["+sender_name+"][M]", sender_message});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AOClient::cmdMute(int argc, QStringList argv)
|
||||||
|
{
|
||||||
|
bool conv_ok = false;
|
||||||
|
int uid = argv[0].toInt(&conv_ok);
|
||||||
|
if (!conv_ok) {
|
||||||
|
sendServerMessage("Invalid user ID.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (server->getClientByID(uid)->is_muted)
|
||||||
|
sendServerMessage("That player is already muted!");
|
||||||
|
else
|
||||||
|
sendServerMessage("Muted player.");
|
||||||
|
server->getClientByID(uid)->is_muted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AOClient::cmdUnmute(int argc, QStringList argv)
|
||||||
|
{
|
||||||
|
bool conv_ok = false;
|
||||||
|
int uid = argv[0].toInt(&conv_ok);
|
||||||
|
if (!conv_ok) {
|
||||||
|
sendServerMessage("Invalid user ID.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!server->getClientByID(uid)->is_muted)
|
||||||
|
sendServerMessage("That player is already unmuted!");
|
||||||
|
else
|
||||||
|
sendServerMessage("Unmuted player.");
|
||||||
|
server->getClientByID(uid)->is_muted = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AOClient::cmdBans(int argc, QStringList argv)
|
||||||
|
{
|
||||||
|
QStringList recent_bans;
|
||||||
|
recent_bans << "Last 5 bans:";
|
||||||
|
recent_bans << "-----";
|
||||||
|
for (DBManager::BanInfo ban : server->db_manager->getRecentBans()) {
|
||||||
|
QString banned_until;
|
||||||
|
if (ban.duration == -2)
|
||||||
|
banned_until = "The heat death of the universe";
|
||||||
|
else
|
||||||
|
banned_until = QDateTime::fromSecsSinceEpoch(ban.time).addSecs(ban.duration).toString("dd.MM.yyyy, hh:mm");
|
||||||
|
recent_bans << "Affected IPID: " + ban.ipid;
|
||||||
|
recent_bans << "Affected HDID: " + ban.hdid;
|
||||||
|
recent_bans << "Reason for ban: " + ban.reason;
|
||||||
|
recent_bans << "Date of ban: " + QDateTime::fromSecsSinceEpoch(ban.time).toString("dd.MM.yyyy, hh:mm");
|
||||||
|
recent_bans << "Ban lasts until: " + banned_until;
|
||||||
|
recent_bans << "-----";
|
||||||
|
}
|
||||||
|
sendServerMessage(recent_bans.join("\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AOClient::cmdUnBan(int argc, QStringList argv)
|
||||||
|
{
|
||||||
|
bool ok;
|
||||||
|
int target_ban = argv[0].toInt(&ok);
|
||||||
|
if (!ok) {
|
||||||
|
sendServerMessage("Invalid ban ID.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (server->db_manager->invalidateBan(target_ban))
|
||||||
|
sendServerMessage("Successfully invalidated ban " + argv[0] + ".");
|
||||||
|
else
|
||||||
|
sendServerMessage("Couldn't invalidate ban " + argv[0] + ", are you sure it exists?");
|
||||||
|
}
|
||||||
|
|
||||||
|
void AOClient::cmdSubTheme(int argc, QStringList argv)
|
||||||
|
{
|
||||||
|
QString subtheme = argv.join(" ");
|
||||||
|
for (AOClient* client : server->clients) {
|
||||||
|
if (client->current_area == current_area)
|
||||||
|
client->sendPacket("ST", {subtheme, "1"});
|
||||||
|
}
|
||||||
|
sendServerMessageArea("Subtheme was set to " + subtheme);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AOClient::cmdAbout(int argc, QStringList argv)
|
||||||
|
{
|
||||||
|
sendPacket("CT", {"The akashi dev team", "Thank you for using akashi! Made with love by scatterflower, with help from in1tiate and Salanto. akashi " + QCoreApplication::applicationVersion()});
|
||||||
|
}
|
||||||
|
|
||||||
QStringList AOClient::buildAreaList(int area_idx)
|
QStringList AOClient::buildAreaList(int area_idx)
|
||||||
{
|
{
|
||||||
QStringList entries;
|
QStringList entries;
|
||||||
@ -869,7 +1052,7 @@ QStringList AOClient::buildAreaList(int area_idx)
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
entries.append("[" + QString::number(area->player_count) + " users][" + area->status + "]");
|
entries.append("[" + QString::number(area->player_count) + " users][" + QVariant::fromValue(area->status).toString().replace("_", "-") + "]");
|
||||||
for (AOClient* client : server->clients) {
|
for (AOClient* client : server->clients) {
|
||||||
if (client->current_area == area_idx && client->joined) {
|
if (client->current_area == area_idx && client->joined) {
|
||||||
QString char_entry = "[" + QString::number(client->id) + "] " + client->current_char;
|
QString char_entry = "[" + QString::number(client->id) + "] " + client->current_char;
|
||||||
@ -968,3 +1151,45 @@ QString AOClient::getAreaTimer(int area_idx, QTimer* timer)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long long AOClient::parseTime(QString input)
|
||||||
|
{
|
||||||
|
QRegularExpression regex("(?:(?:(?<year>.*?)y)*(?:(?<week>.*?)w)*(?:(?<day>.*?)d)*(?:(?<hr>.*?)h)*(?:(?<min>.*?)m)*(?:(?<sec>.*?)s)*)");
|
||||||
|
QRegularExpressionMatch match = regex.match(input);
|
||||||
|
QString str_year, str_week, str_hour, str_day, str_minute, str_second;
|
||||||
|
int year, week, day, hour, minute, second;
|
||||||
|
|
||||||
|
str_year = match.captured("year");
|
||||||
|
str_week = match.captured("week");
|
||||||
|
str_day = match.captured("day");
|
||||||
|
str_hour = match.captured("hr");
|
||||||
|
str_minute = match.captured("min");
|
||||||
|
str_second = match.captured("sec");
|
||||||
|
|
||||||
|
bool is_well_formed = false;
|
||||||
|
QString concat_str(str_year + str_week + str_day + str_hour + str_minute + str_second);
|
||||||
|
concat_str.toInt(&is_well_formed);
|
||||||
|
|
||||||
|
if (!is_well_formed) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
year = str_year.toInt();
|
||||||
|
week = str_week.toInt();
|
||||||
|
day = str_day.toInt();
|
||||||
|
hour = str_hour.toInt();
|
||||||
|
minute = str_minute.toInt();
|
||||||
|
second = str_second.toInt();
|
||||||
|
|
||||||
|
long long total = 0;
|
||||||
|
total += 31622400 * year;
|
||||||
|
total += 604800 * week;
|
||||||
|
total += 86400 * day;
|
||||||
|
total += 3600 * hour;
|
||||||
|
total += 60 * minute;
|
||||||
|
total += second;
|
||||||
|
|
||||||
|
if (total < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
@ -137,8 +137,8 @@ bool ConfigManager::loadServerSettings(server_settings* settings)
|
|||||||
config.value("port", "27016").toInt(&port_conversion_success);
|
config.value("port", "27016").toInt(&port_conversion_success);
|
||||||
settings->ws_port =
|
settings->ws_port =
|
||||||
config.value("webao_port", "27017").toInt(&ws_port_conversion_success);
|
config.value("webao_port", "27017").toInt(&ws_port_conversion_success);
|
||||||
settings->local_port =
|
settings->ms_port =
|
||||||
config.value("port", "27016").toInt(&local_port_conversion_success);
|
config.value("ms_port", "27016").toInt(&local_port_conversion_success);
|
||||||
settings->name = config.value("server_name", "My First Server").toString();
|
settings->name = config.value("server_name", "My First Server").toString();
|
||||||
settings->description =
|
settings->description =
|
||||||
config.value("server_description", "This is my flashy new server")
|
config.value("server_description", "This is my flashy new server")
|
||||||
|
@ -24,32 +24,52 @@ DBManager::DBManager() :
|
|||||||
db.setDatabaseName("config/akashi.db");
|
db.setDatabaseName("config/akashi.db");
|
||||||
if (!db.open())
|
if (!db.open())
|
||||||
qCritical() << "Database Error:" << db.lastError();
|
qCritical() << "Database Error:" << db.lastError();
|
||||||
QSqlQuery create_ban_table("CREATE TABLE IF NOT EXISTS bans ('ID' INTEGER, 'IPID' TEXT, 'HDID' TEXT, 'IP' TEXT, 'TIME' INTEGER, 'REASON' TEXT, PRIMARY KEY('ID' AUTOINCREMENT))");
|
QSqlQuery create_ban_table("CREATE TABLE IF NOT EXISTS bans ('ID' INTEGER, 'IPID' TEXT, 'HDID' TEXT, 'IP' TEXT, 'TIME' INTEGER, 'REASON' TEXT, 'DURATION' INTEGER, PRIMARY KEY('ID' AUTOINCREMENT))");
|
||||||
QSqlQuery create_user_table("CREATE TABLE IF NOT EXISTS users ('ID' INTEGER, 'USERNAME' TEXT, 'SALT' TEXT, 'PASSWORD' TEXT, 'ACL' TEXT, PRIMARY KEY('ID' AUTOINCREMENT))");
|
QSqlQuery create_user_table("CREATE TABLE IF NOT EXISTS users ('ID' INTEGER, 'USERNAME' TEXT, 'SALT' TEXT, 'PASSWORD' TEXT, 'ACL' TEXT, PRIMARY KEY('ID' AUTOINCREMENT))");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DBManager::isIPBanned(QHostAddress ip)
|
bool DBManager::isIPBanned(QHostAddress ip)
|
||||||
{
|
{
|
||||||
QSqlQuery query;
|
QSqlQuery query;
|
||||||
query.prepare("SELECT ID FROM BANS WHERE IP = ?");
|
query.prepare("SELECT TIME FROM BANS WHERE IP = ? ORDER BY TIME DESC");
|
||||||
query.addBindValue(ip.toString());
|
query.addBindValue(ip.toString());
|
||||||
query.exec();
|
query.exec();
|
||||||
return query.first();
|
if (query.first()) {
|
||||||
|
long long duration = getBanDuration(ip);
|
||||||
|
long long ban_time = query.value(0).toLongLong();
|
||||||
|
if (duration == -2)
|
||||||
|
return true;
|
||||||
|
long long current_time = QDateTime::currentDateTime().toSecsSinceEpoch();
|
||||||
|
if (ban_time + duration > current_time)
|
||||||
|
return true;
|
||||||
|
else return false;
|
||||||
|
}
|
||||||
|
else return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DBManager::isHDIDBanned(QString hdid)
|
bool DBManager::isHDIDBanned(QString hdid)
|
||||||
{
|
{
|
||||||
QSqlQuery query;
|
QSqlQuery query;
|
||||||
query.prepare("SELECT ID FROM BANS WHERE HDID = ?");
|
query.prepare("SELECT TIME FROM BANS WHERE HDID = ? ORDER BY TIME DESC");
|
||||||
query.addBindValue(hdid);
|
query.addBindValue(hdid);
|
||||||
query.exec();
|
query.exec();
|
||||||
return query.first();
|
if (query.first()) {
|
||||||
|
long long duration = getBanDuration(hdid);
|
||||||
|
long long ban_time = query.value(0).toLongLong();
|
||||||
|
if (duration == -2)
|
||||||
|
return true;
|
||||||
|
long long current_time = QDateTime::currentDateTime().toSecsSinceEpoch();
|
||||||
|
if (ban_time + duration > current_time)
|
||||||
|
return true;
|
||||||
|
else return false;
|
||||||
|
}
|
||||||
|
else return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString DBManager::getBanReason(QHostAddress ip)
|
QString DBManager::getBanReason(QHostAddress ip)
|
||||||
{
|
{
|
||||||
QSqlQuery query;
|
QSqlQuery query;
|
||||||
query.prepare("SELECT REASON FROM BANS WHERE IP = ?");
|
query.prepare("SELECT REASON FROM BANS WHERE IP = ? ORDER BY TIME DESC");
|
||||||
query.addBindValue(ip.toString());
|
query.addBindValue(ip.toString());
|
||||||
query.exec();
|
query.exec();
|
||||||
if (query.first()) {
|
if (query.first()) {
|
||||||
@ -63,7 +83,7 @@ QString DBManager::getBanReason(QHostAddress ip)
|
|||||||
QString DBManager::getBanReason(QString hdid)
|
QString DBManager::getBanReason(QString hdid)
|
||||||
{
|
{
|
||||||
QSqlQuery query;
|
QSqlQuery query;
|
||||||
query.prepare("SELECT REASON FROM BANS WHERE HDID = ?");
|
query.prepare("SELECT REASON FROM BANS WHERE HDID = ? ORDER BY TIME DESC");
|
||||||
query.addBindValue(hdid);
|
query.addBindValue(hdid);
|
||||||
query.exec();
|
query.exec();
|
||||||
if (query.first()) {
|
if (query.first()) {
|
||||||
@ -74,19 +94,116 @@ QString DBManager::getBanReason(QString hdid)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DBManager::addBan(QString ipid, QHostAddress ip, QString hdid, unsigned long time, QString reason)
|
long long DBManager::getBanDuration(QString hdid)
|
||||||
{
|
{
|
||||||
QSqlQuery query;
|
QSqlQuery query;
|
||||||
query.prepare("INSERT INTO BANS(IPID, HDID, IP, TIME, REASON) VALUES(?, ?, ?, ?, ?)");
|
query.prepare("SELECT DURATION FROM BANS WHERE HDID = ? ORDER BY TIME DESC");
|
||||||
query.addBindValue(ipid);
|
|
||||||
query.addBindValue(hdid);
|
query.addBindValue(hdid);
|
||||||
|
query.exec();
|
||||||
|
if (query.first()) {
|
||||||
|
return query.value(0).toLongLong();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
long long DBManager::getBanDuration(QHostAddress ip)
|
||||||
|
{
|
||||||
|
QSqlQuery query;
|
||||||
|
query.prepare("SELECT DURATION FROM BANS WHERE IP = ? ORDER BY TIME DESC");
|
||||||
query.addBindValue(ip.toString());
|
query.addBindValue(ip.toString());
|
||||||
query.addBindValue(QString::number(time));
|
query.exec();
|
||||||
query.addBindValue(reason);
|
if (query.first()) {
|
||||||
|
return query.value(0).toLongLong();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int DBManager::getBanID(QString hdid)
|
||||||
|
{
|
||||||
|
QSqlQuery query;
|
||||||
|
query.prepare("SELECT ID FROM BANS WHERE HDID = ?");
|
||||||
|
query.addBindValue(hdid);
|
||||||
|
query.exec();
|
||||||
|
if (query.first()) {
|
||||||
|
return query.value(0).toInt();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int DBManager::getBanID(QHostAddress ip)
|
||||||
|
{
|
||||||
|
QSqlQuery query;
|
||||||
|
query.prepare("SELECT ID FROM BANS WHERE IP = ?");
|
||||||
|
query.addBindValue(ip.toString());
|
||||||
|
query.exec();
|
||||||
|
if (query.first()) {
|
||||||
|
return query.value(0).toInt();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<DBManager::BanInfo> DBManager::getRecentBans()
|
||||||
|
{
|
||||||
|
QList<BanInfo> return_list;
|
||||||
|
QSqlQuery query;
|
||||||
|
query.prepare("SELECT TOP(5) * FROM BANS ORDER BY TIME DESC");
|
||||||
|
query.setForwardOnly(true);
|
||||||
|
query.exec();
|
||||||
|
while (query.next()) {
|
||||||
|
BanInfo ban;
|
||||||
|
ban.ipid = query.value(0).toString();
|
||||||
|
ban.hdid = query.value(1).toString();
|
||||||
|
ban.ip = QHostAddress(query.value(2).toString());
|
||||||
|
ban.time = static_cast<unsigned long>(query.value(3).toULongLong());
|
||||||
|
ban.reason = query.value(4).toString();
|
||||||
|
ban.duration = query.value(5).toLongLong();
|
||||||
|
return_list.append(ban);
|
||||||
|
}
|
||||||
|
std::reverse(return_list.begin(), return_list.end());
|
||||||
|
return return_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBManager::addBan(BanInfo ban)
|
||||||
|
{
|
||||||
|
QSqlQuery query;
|
||||||
|
query.prepare("INSERT INTO BANS(IPID, HDID, IP, TIME, REASON, DURATION) VALUES(?, ?, ?, ?, ?, ?)");
|
||||||
|
query.addBindValue(ban.ipid);
|
||||||
|
query.addBindValue(ban.hdid);
|
||||||
|
query.addBindValue(ban.ip.toString());
|
||||||
|
query.addBindValue(QString::number(ban.time));
|
||||||
|
query.addBindValue(ban.reason);
|
||||||
|
query.addBindValue(ban.duration);
|
||||||
if (!query.exec())
|
if (!query.exec())
|
||||||
qDebug() << "SQL Error:" << query.lastError().text();
|
qDebug() << "SQL Error:" << query.lastError().text();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DBManager::invalidateBan(int id)
|
||||||
|
{
|
||||||
|
QSqlQuery ban_exists;
|
||||||
|
ban_exists.prepare("SELECT DURATION FROM bans WHERE ID = ?");
|
||||||
|
ban_exists.addBindValue(id);
|
||||||
|
ban_exists.exec();
|
||||||
|
|
||||||
|
if (ban_exists.first())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
QSqlQuery query;
|
||||||
|
query.prepare("UPDATE bans SET DURATION = 0 WHERE ID = ?");
|
||||||
|
query.addBindValue(id);
|
||||||
|
query.exec();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool DBManager::createUser(QString username, QString salt, QString password, unsigned long long acl)
|
bool DBManager::createUser(QString username, QString salt, QString password, unsigned long long acl)
|
||||||
{
|
{
|
||||||
QSqlQuery username_exists;
|
QSqlQuery username_exists;
|
||||||
@ -115,6 +232,23 @@ bool DBManager::createUser(QString username, QString salt, QString password, uns
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DBManager::deleteUser(QString username)
|
||||||
|
{
|
||||||
|
QSqlQuery username_exists;
|
||||||
|
username_exists.prepare("SELECT ACL FROM users WHERE USERNAME = ?");
|
||||||
|
username_exists.addBindValue(username);
|
||||||
|
username_exists.exec();
|
||||||
|
|
||||||
|
if (username_exists.first())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
QSqlQuery query;
|
||||||
|
query.prepare("DELETE FROM users WHERE USERNAME = ?");
|
||||||
|
username_exists.addBindValue(username);
|
||||||
|
username_exists.exec();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
unsigned long long DBManager::getACL(QString moderator_name)
|
unsigned long long DBManager::getACL(QString moderator_name)
|
||||||
{
|
{
|
||||||
if (moderator_name == "")
|
if (moderator_name == "")
|
||||||
|
@ -36,7 +36,7 @@ int main(int argc, char* argv[])
|
|||||||
{
|
{
|
||||||
QCoreApplication app(argc, argv);
|
QCoreApplication app(argc, argv);
|
||||||
QCoreApplication::setApplicationName("akashi");
|
QCoreApplication::setApplicationName("akashi");
|
||||||
QCoreApplication::setApplicationVersion("0.0.1");
|
QCoreApplication::setApplicationVersion("apricot r2 prerelease");
|
||||||
std::atexit(cleanup);
|
std::atexit(cleanup);
|
||||||
|
|
||||||
ConfigManager config_manager;
|
ConfigManager config_manager;
|
||||||
@ -55,8 +55,8 @@ int main(int argc, char* argv[])
|
|||||||
else {
|
else {
|
||||||
if (settings.advertise_server) {
|
if (settings.advertise_server) {
|
||||||
advertiser =
|
advertiser =
|
||||||
new Advertiser(settings.ms_ip, settings.port,
|
new Advertiser(settings.ms_ip, settings.ms_port,
|
||||||
settings.ws_port, settings.local_port,
|
settings.ws_port, settings.port,
|
||||||
settings.name, settings.description);
|
settings.name, settings.description);
|
||||||
advertiser->contactMasterServer();
|
advertiser->contactMasterServer();
|
||||||
}
|
}
|
||||||
|
101
src/packets.cpp
101
src/packets.cpp
@ -26,9 +26,9 @@ void AOClient::pktDefault(AreaData* area, int argc, QStringList argv, AOPacket p
|
|||||||
|
|
||||||
void AOClient::pktHardwareId(AreaData* area, int argc, QStringList argv, AOPacket packet)
|
void AOClient::pktHardwareId(AreaData* area, int argc, QStringList argv, AOPacket packet)
|
||||||
{
|
{
|
||||||
setHwid(argv[0]);
|
hwid = argv[0];
|
||||||
if(server->db_manager->isHDIDBanned(getHwid())) {
|
if(server->db_manager->isHDIDBanned(hwid)) {
|
||||||
sendPacket("BD", {server->db_manager->getBanReason(getHwid())});
|
sendPacket("BD", {server->db_manager->getBanReason(hwid)});
|
||||||
socket->close();
|
socket->close();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -51,32 +51,18 @@ void AOClient::pktSoftwareId(AreaData* area, int argc, QStringList argv, AOPacke
|
|||||||
"deskmod", "evidence", "cccc_ic_support",
|
"deskmod", "evidence", "cccc_ic_support",
|
||||||
"arup", "casing_alerts", "modcall_reason",
|
"arup", "casing_alerts", "modcall_reason",
|
||||||
"looping_sfx", "additive", "effects",
|
"looping_sfx", "additive", "effects",
|
||||||
"y_offset"
|
"y_offset", "expanded_desk_mods", "auth_packet"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// Extremely cursed client version string validation
|
|
||||||
// Ideally version strings should be X.X.X but it can be literally anything
|
|
||||||
// so we have to be super careful
|
|
||||||
version.string = argv[1];
|
version.string = argv[1];
|
||||||
QStringList version_raw = version.string.split(".");
|
QRegularExpression rx("\\b(\\d+)\\.(\\d+)\\.(\\d+)\\b"); // matches X.X.X (e.g. 2.9.0, 2.4.10, etc.)
|
||||||
bool ok;
|
QRegularExpressionMatch match = rx.match(version.string);
|
||||||
int release_version = version_raw[0].toInt(&ok);
|
if (match.hasMatch()) {
|
||||||
if (ok && version_raw.size() >= 1)
|
version.release = match.captured(1).toInt();
|
||||||
version.release = release_version;
|
version.major = match.captured(2).toInt();
|
||||||
if (ok && version_raw.size() >= 2) {
|
version.minor = match.captured(3).toInt();
|
||||||
int major_version = version_raw[1].toInt(&ok);
|
|
||||||
if (ok)
|
|
||||||
version.major = major_version;
|
|
||||||
}
|
}
|
||||||
if (ok && version_raw.size() >= 3) {
|
|
||||||
int minor_version = version_raw[2].toInt(&ok);
|
|
||||||
if (ok)
|
|
||||||
version.minor = minor_version;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
sendPacket("PN", {QString::number(server->player_count), max_players});
|
sendPacket("PN", {QString::number(server->player_count), max_players});
|
||||||
sendPacket("FL", feature_list);
|
sendPacket("FL", feature_list);
|
||||||
@ -102,7 +88,7 @@ void AOClient::pktRequestMusic(AreaData* area, int argc, QStringList argv, AOPac
|
|||||||
|
|
||||||
void AOClient::pktLoadingDone(AreaData* area, int argc, QStringList argv, AOPacket packet)
|
void AOClient::pktLoadingDone(AreaData* area, int argc, QStringList argv, AOPacket packet)
|
||||||
{
|
{
|
||||||
if (getHwid() == "") {
|
if (hwid == "") {
|
||||||
// No early connecting!
|
// No early connecting!
|
||||||
socket->close();
|
socket->close();
|
||||||
return;
|
return;
|
||||||
@ -116,16 +102,37 @@ void AOClient::pktLoadingDone(AreaData* area, int argc, QStringList argv, AOPack
|
|||||||
area->player_count++;
|
area->player_count++;
|
||||||
joined = true;
|
joined = true;
|
||||||
server->updateCharsTaken(area);
|
server->updateCharsTaken(area);
|
||||||
fullArup(); // Give client all the area data
|
|
||||||
arup(ARUPType::PLAYER_COUNT, true); // Tell everyone there is a new player
|
arup(ARUPType::PLAYER_COUNT, true); // Tell everyone there is a new player
|
||||||
sendEvidenceList(area);
|
sendEvidenceList(area);
|
||||||
|
|
||||||
sendPacket("HP", {"1", QString::number(area->def_hp)});
|
sendPacket("HP", {"1", QString::number(area->def_hp)});
|
||||||
sendPacket("HP", {"2", QString::number(area->pro_hp)});
|
sendPacket("HP", {"2", QString::number(area->pro_hp)});
|
||||||
sendPacket("FA", server->area_names);
|
sendPacket("FA", server->area_names);
|
||||||
sendPacket("BN", {area->background});
|
|
||||||
sendPacket("OPPASS", {"DEADBEEF"});
|
sendPacket("OPPASS", {"DEADBEEF"});
|
||||||
sendPacket("DONE");
|
sendPacket("DONE");
|
||||||
|
sendPacket("BN", {area->background});
|
||||||
|
|
||||||
|
sendServerMessage("=== MOTD ===\r\n" + server->MOTD + "\r\n=============");
|
||||||
|
|
||||||
|
fullArup(); // Give client all the area data
|
||||||
|
if (server->timer->isActive()) {
|
||||||
|
sendPacket("TI", {"0", "2"});
|
||||||
|
sendPacket("TI", {"0", "0", QString::number(QTime(0,0).msecsTo(QTime(0,0).addMSecs(server->timer->remainingTime())))});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sendPacket("TI", {"0", "3"});
|
||||||
|
}
|
||||||
|
for (QTimer* timer : area->timers) {
|
||||||
|
int timer_id = area->timers.indexOf(timer) + 1;
|
||||||
|
if (timer->isActive()) {
|
||||||
|
sendPacket("TI", {QString::number(timer_id), "2"});
|
||||||
|
sendPacket("TI", {QString::number(timer_id), "0", QString::number(QTime(0,0).msecsTo(QTime(0,0).addMSecs(timer->remainingTime())))});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sendPacket("TI", {QString::number(timer_id), "3"});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AOClient::pktCharPassword(AreaData* area, int argc, QStringList argv, AOPacket packet)
|
void AOClient::pktCharPassword(AreaData* area, int argc, QStringList argv, AOPacket packet)
|
||||||
@ -147,6 +154,11 @@ void AOClient::pktSelectChar(AreaData* area, int argc, QStringList argv, AOPacke
|
|||||||
|
|
||||||
void AOClient::pktIcChat(AreaData* area, int argc, QStringList argv, AOPacket packet)
|
void AOClient::pktIcChat(AreaData* area, int argc, QStringList argv, AOPacket packet)
|
||||||
{
|
{
|
||||||
|
if (is_muted) {
|
||||||
|
sendServerMessage("You cannot speak while muted.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
AOPacket validated_packet = validateIcPacket(packet);
|
AOPacket validated_packet = validateIcPacket(packet);
|
||||||
if (validated_packet.header == "INVALID")
|
if (validated_packet.header == "INVALID")
|
||||||
return;
|
return;
|
||||||
@ -161,8 +173,7 @@ void AOClient::pktIcChat(AreaData* area, int argc, QStringList argv, AOPacket pa
|
|||||||
void AOClient::pktOocChat(AreaData* area, int argc, QStringList argv, AOPacket packet)
|
void AOClient::pktOocChat(AreaData* area, int argc, QStringList argv, AOPacket packet)
|
||||||
{
|
{
|
||||||
ooc_name = dezalgo(argv[0]).replace(QRegExp("\\[|\\]|\\{|\\}|\\#|\\$|\\%|\\&"), ""); // no fucky wucky shit here
|
ooc_name = dezalgo(argv[0]).replace(QRegExp("\\[|\\]|\\{|\\}|\\#|\\$|\\%|\\&"), ""); // no fucky wucky shit here
|
||||||
|
if (ooc_name.isEmpty() || ooc_name == server->getServerName()) // impersonation & empty name protection
|
||||||
if (ooc_name == server->getServerName()) // impersonation prevention
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QString message = dezalgo(argv[1]);
|
QString message = dezalgo(argv[1]);
|
||||||
@ -203,9 +214,19 @@ void AOClient::pktChangeMusic(AreaData* area, int argc, QStringList argv, AOPack
|
|||||||
for (QString song : server->music_list) {
|
for (QString song : server->music_list) {
|
||||||
if (song == argument || song == "~stop.mp3") { // ~stop.mp3 is a dummy track used by 2.9+
|
if (song == argument || song == "~stop.mp3") { // ~stop.mp3 is a dummy track used by 2.9+
|
||||||
// We have a song here
|
// We have a song here
|
||||||
AOPacket music_change("MC", {song, argv[1], argv[2], "1", "0", argv[3]});
|
QString effects;
|
||||||
area->current_music = song;
|
if (argc >= 4)
|
||||||
area->music_played_by = argv[2];
|
effects = argv[3];
|
||||||
|
else
|
||||||
|
effects = "0";
|
||||||
|
QString final_song;
|
||||||
|
if (!argument.contains("."))
|
||||||
|
final_song = "~stop.mp3";
|
||||||
|
else
|
||||||
|
final_song = argument;
|
||||||
|
AOPacket music_change("MC", {final_song, argv[1], showname, "1", "0", effects});
|
||||||
|
area->current_music = final_song;
|
||||||
|
area->music_played_by = showname;
|
||||||
server->broadcast(music_change, current_area);
|
server->broadcast(music_change, current_area);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -254,6 +275,7 @@ void AOClient::pktWebSocketIp(AreaData* area, int argc, QStringList argv, AOPack
|
|||||||
qDebug() << "ws ip set to" << argv[0];
|
qDebug() << "ws ip set to" << argv[0];
|
||||||
#endif
|
#endif
|
||||||
remote_ip = QHostAddress(argv[0]);
|
remote_ip = QHostAddress(argv[0]);
|
||||||
|
calculateIpid();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -360,15 +382,14 @@ AOPacket AOClient::validateIcPacket(AOPacket packet)
|
|||||||
incoming_args.append(QVariant(arg));
|
incoming_args.append(QVariant(arg));
|
||||||
}
|
}
|
||||||
|
|
||||||
// message type
|
// desk modifier
|
||||||
if (incoming_args[0].toInt() == 1)
|
QStringList allowed_desk_mods;
|
||||||
args.append("1");
|
allowed_desk_mods << "chat" << "0" << "1" << "2" << "3" << "4" << "5";
|
||||||
else if (incoming_args[0].toInt() == 0) {
|
if (allowed_desk_mods.contains(incoming_args[0].toString())) {
|
||||||
if (incoming_args[0].toString() == "chat")
|
args.append(incoming_args[0].toString());
|
||||||
args.append("chat");
|
|
||||||
else
|
|
||||||
args.append("0");
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
return invalid;
|
||||||
|
|
||||||
// preanim
|
// preanim
|
||||||
args.append(incoming_args[1].toString());
|
args.append(incoming_args[1].toString());
|
||||||
|
@ -51,6 +51,8 @@ void Server::start()
|
|||||||
qDebug() << "Server listening on" << port;
|
qDebug() << "Server listening on" << port;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MOTD = config.value("motd","MOTD is not set.").toString();
|
||||||
|
|
||||||
proxy = new WSProxy(port, ws_port, this);
|
proxy = new WSProxy(port, ws_port, this);
|
||||||
if(ws_port != -1)
|
if(ws_port != -1)
|
||||||
proxy->start();
|
proxy->start();
|
||||||
@ -79,10 +81,20 @@ void Server::start()
|
|||||||
bg_file.close();
|
bg_file.close();
|
||||||
|
|
||||||
QSettings areas_ini("config/areas.ini", QSettings::IniFormat);
|
QSettings areas_ini("config/areas.ini", QSettings::IniFormat);
|
||||||
area_names = areas_ini.childGroups();
|
area_names = areas_ini.childGroups(); // invisibly does a lexicographical sort, because Qt is great like that
|
||||||
for (int i = 0; i < area_names.length(); i++) {
|
std::sort(area_names.begin(), area_names.end(), [] (const QString &a, const QString &b) {return a.split(":")[0].toInt() < b.split(":")[0].toInt();});
|
||||||
QString area_name = area_names[i];
|
QStringList sanitized_area_names;
|
||||||
areas.insert(i, new AreaData(characters, area_name, i));
|
QStringList raw_area_names = area_names;
|
||||||
|
for (QString area_name : area_names) {
|
||||||
|
QStringList name_split = area_name.split(":");
|
||||||
|
name_split.removeFirst();
|
||||||
|
QString area_name_sanitized = name_split.join(":");
|
||||||
|
sanitized_area_names.append(area_name_sanitized);
|
||||||
|
}
|
||||||
|
area_names = sanitized_area_names;
|
||||||
|
for (int i = 0; i < raw_area_names.length(); i++) {
|
||||||
|
QString area_name = raw_area_names[i];
|
||||||
|
areas.insert(i, new AreaData(area_name, i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,8 +142,8 @@ void Server::clientConnected()
|
|||||||
void Server::updateCharsTaken(AreaData* area)
|
void Server::updateCharsTaken(AreaData* area)
|
||||||
{
|
{
|
||||||
QStringList chars_taken;
|
QStringList chars_taken;
|
||||||
for (QString cur_char : area->characters_taken.keys()) {
|
for (QString cur_char : characters) {
|
||||||
chars_taken.append(area->characters_taken.value(cur_char)
|
chars_taken.append(area->characters_taken.contains(getCharID(cur_char))
|
||||||
? QStringLiteral("-1")
|
? QStringLiteral("-1")
|
||||||
: QStringLiteral("0"));
|
: QStringLiteral("0"));
|
||||||
}
|
}
|
||||||
@ -173,13 +185,14 @@ int Server::getDiceValue(QString value_type)
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
AOClient* Server::getClient(QString ipid)
|
QList<AOClient*> Server::getClientsByIpid(QString ipid)
|
||||||
{
|
{
|
||||||
|
QList<AOClient*> return_clients;
|
||||||
for (AOClient* client : clients) {
|
for (AOClient* client : clients) {
|
||||||
if (client->getIpid() == ipid)
|
if (client->getIpid() == ipid)
|
||||||
return client;
|
return_clients.append(client);
|
||||||
}
|
}
|
||||||
return nullptr;
|
return return_clients;
|
||||||
}
|
}
|
||||||
|
|
||||||
AOClient* Server::getClientByID(int id)
|
AOClient* Server::getClientByID(int id)
|
||||||
|
Loading…
Reference in New Issue
Block a user