diff --git a/core.pro b/core.pro index 127946ee..cb96c846 100644 --- a/core.pro +++ b/core.pro @@ -47,6 +47,7 @@ SOURCES += \ src/config_manager.cpp \ src/db_manager.cpp \ src/discord.cpp \ + src/packet/packet_pr.cpp \ src/packets.cpp \ src/playerstateobserver.cpp \ src/server.cpp \ @@ -68,10 +69,10 @@ SOURCES += \ src/packet/packet_de.cpp \ src/packet/packet_ee.cpp \ src/packet/packet_hp.cpp \ + src/packet/packet_ma.cpp \ src/packet/packet_mc.cpp \ src/packet/packet_ms.cpp \ src/packet/packet_pe.cpp \ - src/packet/packet_pl.cpp \ src/packet/packet_pw.cpp \ src/packet/packet_rc.cpp \ src/packet/packet_rd.cpp \ @@ -92,6 +93,7 @@ HEADERS += src/aoclient.h \ src/data_types.h \ src/db_manager.h \ src/discord.h \ + src/packet/packet_pr.h \ src/playerstateobserver.h \ src/server.h \ src/typedefs.h \ @@ -113,10 +115,10 @@ HEADERS += src/aoclient.h \ src/packet/packet_de.h \ src/packet/packet_ee.h \ src/packet/packet_hp.h \ + src/packet/packet_ma.h \ src/packet/packet_mc.h \ src/packet/packet_ms.h \ src/packet/packet_pe.h \ - src/packet/packet_pl.h \ src/packet/packet_pw.h \ src/packet/packet_rc.h \ src/packet/packet_rd.h \ diff --git a/src/commands/moderation.cpp b/src/commands/moderation.cpp index cca4dbcf..d998ecb2 100644 --- a/src/commands/moderation.cpp +++ b/src/commands/moderation.cpp @@ -77,7 +77,7 @@ void AOClient::cmdBan(int argc, QStringList argv) l_ban_duration = QDateTime::fromSecsSinceEpoch(l_ban.time).addSecs(l_ban.duration).toString("MM/dd/yyyy, hh:mm"); } else { - l_ban_duration = "The heat death of the universe."; + l_ban_duration = "Permanently."; } int l_ban_id = server->getDatabaseManager()->getBanID(l_ban.ip); l_client->sendPacket("KB", {l_ban.reason + "\nID: " + QString::number(l_ban_id) + "\nUntil: " + l_ban_duration}); diff --git a/src/network/aopacket.cpp b/src/network/aopacket.cpp index 7bf85b20..9b630ac6 100644 --- a/src/network/aopacket.cpp +++ b/src/network/aopacket.cpp @@ -28,10 +28,11 @@ #include "packet/packet_hi.h" #include "packet/packet_hp.h" #include "packet/packet_id.h" +#include "packet/packet_ma.h" #include "packet/packet_mc.h" #include "packet/packet_ms.h" #include "packet/packet_pe.h" -#include "packet/packet_pl.h" +#include "packet/packet_pr.h" #include "packet/packet_pw.h" #include "packet/packet_rc.h" #include "packet/packet_rd.h" @@ -46,6 +47,8 @@ AOPacket::AOPacket(QStringList p_contents) : { } +AOPacket::~AOPacket() {} + const QStringList AOPacket::getContent() { return m_content; @@ -132,8 +135,8 @@ void AOPacket::registerPackets() PacketFactory::registerClass("RM"); PacketFactory::registerClass("RT"); PacketFactory::registerClass("SETCASE"); + PacketFactory::registerClass("MA"); PacketFactory::registerClass("ZZ"); - PacketFactory::registerClass("PL"); - PacketFactory::registerClass("PLU"); + PacketFactory::registerClass("PR"); PacketFactory::registerClass("PU"); } diff --git a/src/network/aopacket.h b/src/network/aopacket.h index c97a4794..b24c7d90 100644 --- a/src/network/aopacket.h +++ b/src/network/aopacket.h @@ -43,7 +43,7 @@ class AOPacket /** * @brief Destructor for the AOPacket */ - ~AOPacket(){}; + virtual ~AOPacket(); /** * @brief Returns the current content of the packet diff --git a/src/packet/packet_hi.cpp b/src/packet/packet_hi.cpp index 5c7a2c4a..6a5060e2 100644 --- a/src/packet/packet_hi.cpp +++ b/src/packet/packet_hi.cpp @@ -40,7 +40,7 @@ void PacketHI::handlePacket(AreaData *area, AOClient &client) const ban_duration = QDateTime::fromSecsSinceEpoch(ban.second.time).addSecs(ban.second.duration).toString("MM/dd/yyyy, hh:mm"); } else { - ban_duration = "The heat death of the universe."; + ban_duration = "Permanently."; } client.sendPacket("BD", {"Reason: " + ban.second.reason + "\nBan ID: " + QString::number(ban.second.id) + "\nUntil: " + ban_duration}); client.m_socket->close(); diff --git a/src/packet/packet_ma.cpp b/src/packet/packet_ma.cpp new file mode 100644 index 00000000..c013ae51 --- /dev/null +++ b/src/packet/packet_ma.cpp @@ -0,0 +1,115 @@ +#include "packet_ma.h" + +#include "config_manager.h" +#include "db_manager.h" +#include "server.h" + +PacketMA::PacketMA(QStringList &contents) : + AOPacket(contents) +{ +} + +PacketInfo PacketMA::getPacketInfo() const +{ + PacketInfo info{ + .acl_permission = ACLRole::Permission::NONE, + .min_args = 3, + .header = "MA"}; + return info; +} + +void PacketMA::handlePacket(AreaData *area, AOClient &client) const +{ + if (!client.m_authenticated) { + client.sendServerMessage("You are not logged in!"); + return; + } + + int client_id = m_content.at(0).toInt(); + int duration = qMax(m_content.at(1).toInt(), -1); + QString reason = m_content.at(2); + + bool is_kick = duration == 0; + if (is_kick) { + if (!client.checkPermission(ACLRole::KICK)) { + client.sendServerMessage("You do not have permission to kick users."); + return; + } + } + else { + if (!client.checkPermission(ACLRole::BAN)) { + client.sendServerMessage("You do not have permission to ban users."); + return; + } + } + + AOClient *target = client.getServer()->getClientByID(client_id); + if (target == nullptr) { + client.sendServerMessage("User not found."); + return; + } + + QString moderator_name; + if (ConfigManager::authType() == DataTypes::AuthType::ADVANCED) { + moderator_name = client.m_moderator_name; + } + else { + moderator_name = "Moderator"; + } + + QList clients = client.getServer()->getClientsByIpid(target->m_ipid); + if (is_kick) { + for (AOClient *subclient : clients) { + subclient->sendPacket("KK", {reason}); + subclient->m_socket->close(); + } + + Q_EMIT client.logKick(moderator_name, target->m_ipid, reason); + + client.sendServerMessage("Kicked " + QString::number(clients.size()) + " client(s) with ipid " + target->m_ipid + " for reason: " + reason); + } + else { + DBManager::BanInfo ban; + + ban.ip = target->m_remote_ip; + ban.ipid = target->m_ipid; + ban.moderator = moderator_name; + ban.reason = reason; + ban.time = QDateTime::currentDateTime().toSecsSinceEpoch(); + + QString timestamp; + if (duration == -1) { + ban.duration = -2; + timestamp = "permanently"; + } + else { + ban.duration = duration * 60; + timestamp = QDateTime::fromSecsSinceEpoch(ban.time).addSecs(ban.duration).toString("MM/dd/yyyy, hh:mm"); + } + + for (AOClient *subclient : clients) { + ban.hdid = subclient->m_hwid; + + client.getServer()->getDatabaseManager()->addBan(ban); + + subclient->sendPacket("KB", {reason}); + subclient->m_socket->close(); + } + + if (ban.duration == -2) { + timestamp = "permanently"; + } + else { + timestamp = QString::number(ban.time + ban.duration); + } + + Q_EMIT client.logBan(moderator_name, target->m_ipid, timestamp, reason); + + client.sendServerMessage("Banned " + QString::number(clients.size()) + " client(s) with ipid " + target->m_ipid + " for reason: " + reason); + + int ban_id = client.getServer()->getDatabaseManager()->getBanID(ban.ip); + if (ConfigManager::discordBanWebhookEnabled()) { + Q_EMIT client.getServer()->banWebhookRequest(ban.ipid, ban.moderator, timestamp, ban.reason, ban_id); + } + } +} diff --git a/src/packet/packet_ma.h b/src/packet/packet_ma.h new file mode 100644 index 00000000..79249065 --- /dev/null +++ b/src/packet/packet_ma.h @@ -0,0 +1,11 @@ +#pragma once + +#include "network/aopacket.h" + +class PacketMA : public AOPacket +{ + public: + PacketMA(QStringList &contents); + virtual PacketInfo getPacketInfo() const; + virtual void handlePacket(AreaData *area, AOClient &client) const; +}; diff --git a/src/packet/packet_pl.cpp b/src/packet/packet_pl.cpp deleted file mode 100644 index 9d979abd..00000000 --- a/src/packet/packet_pl.cpp +++ /dev/null @@ -1,88 +0,0 @@ -#include "packet_pl.h" - -#include - -PacketPL::PacketPL(QStringList &contents) : - AOPacket(contents) -{} - -PacketPL::PacketPL(const QList &f_player_list) : - AOPacket(QStringList{""}) -{ - - QJsonArray player_list_json; - for (const PlayerData &player : f_player_list) { - QJsonObject player_json; - - player_json["id"] = player.id; - player_json["name"] = player.name; - player_json["character"] = player.character; - player_json["character_name"] = player.character_name; - player_json["area_id"] = player.area_id; - - player_list_json.append(player_json); - } - - setContentField(0, QJsonDocument(player_list_json).toJson(QJsonDocument::Compact)); -} - -PacketInfo PacketPL::getPacketInfo() const { return PacketInfo{.acl_permission = ACLRole::NONE, .min_args = 1, .header = "PL"}; } - -void PacketPL::handlePacket(AreaData *area, AOClient &client) const -{ - Q_UNUSED(area); - Q_UNUSED(client); -} - -PacketPLU::PacketPLU(QStringList &contents) : - AOPacket(contents) -{} - -PacketPLU::PacketPLU(int f_id, UpdateType f_type) : - AOPacket(QStringList{""}) -{ - QJsonObject data_json; - data_json["id"] = f_id; - data_json["type"] = f_type; - - setContentField(0, QJsonDocument(data_json).toJson(QJsonDocument::Compact)); -} - -PacketInfo PacketPLU::getPacketInfo() const { return PacketInfo{.acl_permission = ACLRole::NONE, .min_args = 1, .header = "PLU"}; } - -void PacketPLU::handlePacket(AreaData *area, AOClient &client) const -{ - Q_UNUSED(area); - Q_UNUSED(client); -} - -PacketPU::PacketPU(QStringList &contents) : - AOPacket(contents) -{} - -PacketPU::PacketPU(int f_id, DataType f_type, const QString &f_data) : - AOPacket(QStringList{""}) -{ - QJsonObject data_json; - data_json["id"] = f_id; - data_json["type"] = f_type; - data_json["data"] = f_data; - - setContentField(0, QJsonDocument(data_json).toJson(QJsonDocument::Compact)); -} - -PacketPU::PacketPU(int f_id, DataType f_type, int f_data) : - PacketPU(f_id, f_type, QString::number(f_data)) -{ -} - -PacketInfo PacketPU::getPacketInfo() const -{ - return PacketInfo{.acl_permission = ACLRole::NONE, .min_args = 1, .header = "PU"}; -} - -void PacketPU::handlePacket(AreaData *area, AOClient &client) const -{ - Q_UNUSED(area); - Q_UNUSED(client); -} diff --git a/src/packet/packet_pl.h b/src/packet/packet_pl.h deleted file mode 100644 index be6337d4..00000000 --- a/src/packet/packet_pl.h +++ /dev/null @@ -1,59 +0,0 @@ -#pragma once - -#include "network/aopacket.h" - -#include -#include -#include -#include - -class PacketPL : public AOPacket -{ - public: - struct PlayerData - { - int id; - QString name; - QString character; - QString character_name; - int area_id = -1; - }; - - PacketPL(QStringList &contents); - PacketPL(const QList &f_player_list); - PacketInfo getPacketInfo() const override; - void handlePacket(AreaData *area, AOClient &client) const override; -}; - -class PacketPLU : public AOPacket -{ - public: - enum UpdateType - { - AddPlayerUpdate, - RemovePlayerUpdate, - }; - - PacketPLU(QStringList &contents); - PacketPLU(int f_id, UpdateType f_type); - PacketInfo getPacketInfo() const override; - void handlePacket(AreaData *area, AOClient &client) const override; -}; - -class PacketPU : public AOPacket -{ - public: - enum DataType - { - NameData, - CharacterData, - CharacterNameData, - AreaIdData, - }; - - PacketPU(QStringList &contents); - PacketPU(int f_id, DataType f_type, const QString &f_data); - PacketPU(int f_id, DataType f_type, int f_data); - PacketInfo getPacketInfo() const override; - void handlePacket(AreaData *area, AOClient &client) const override; -}; diff --git a/src/packet/packet_pr.cpp b/src/packet/packet_pr.cpp new file mode 100644 index 00000000..a3318b7d --- /dev/null +++ b/src/packet/packet_pr.cpp @@ -0,0 +1,41 @@ +#include "packet_pr.h" + +PacketPR::PacketPR(QStringList &contents) : + AOPacket(contents) +{} + +PacketPR::PacketPR(int f_id, UPDATE_TYPE f_update) : + AOPacket(QStringList{QString::number(f_id), QString::number(f_update)}) +{} + +PacketInfo PacketPR::getPacketInfo() const { return PacketInfo{.acl_permission = ACLRole::NONE, .min_args = 2, .header = "PR"}; } + +void PacketPR::handlePacket(AreaData *area, AOClient &client) const +{ + Q_UNUSED(area); + Q_UNUSED(client); +} + +PacketPU::PacketPU(QStringList &contents) : + AOPacket(contents) +{} + +PacketPU::PacketPU(int f_id, DATA_TYPE f_type, const QString &f_data) : + AOPacket(QStringList{QString::number(f_id), QString::number(f_type), f_data}) +{} + +PacketPU::PacketPU(int f_id, DATA_TYPE f_type, int f_data) : + PacketPU(f_id, f_type, QString::number(f_data)) +{ +} + +PacketInfo PacketPU::getPacketInfo() const +{ + return PacketInfo{.acl_permission = ACLRole::NONE, .min_args = 3, .header = "PU"}; +} + +void PacketPU::handlePacket(AreaData *area, AOClient &client) const +{ + Q_UNUSED(area); + Q_UNUSED(client); +} diff --git a/src/packet/packet_pr.h b/src/packet/packet_pr.h new file mode 100644 index 00000000..9c713234 --- /dev/null +++ b/src/packet/packet_pr.h @@ -0,0 +1,38 @@ +#pragma once + +#include "network/aopacket.h" + +#include + +class PacketPR : public AOPacket +{ + public: + enum UPDATE_TYPE + { + ADD, + REMOVE, + }; + + PacketPR(QStringList &contents); + PacketPR(int f_id, UPDATE_TYPE f_update); + PacketInfo getPacketInfo() const override; + void handlePacket(AreaData *area, AOClient &client) const override; +}; + +class PacketPU : public AOPacket +{ + public: + enum DATA_TYPE + { + NAME, + CHARACTER, + CHARACTER_NAME, + AREA_ID, + }; + + PacketPU(QStringList &contents); + PacketPU(int f_id, DATA_TYPE f_type, const QString &f_data); + PacketPU(int f_id, DATA_TYPE f_type, int f_data); + PacketInfo getPacketInfo() const override; + void handlePacket(AreaData *area, AOClient &client) const override; +}; diff --git a/src/packet/packet_zz.cpp b/src/packet/packet_zz.cpp index 92bc4ef5..a308e6b7 100644 --- a/src/packet/packet_zz.cpp +++ b/src/packet/packet_zz.cpp @@ -14,7 +14,7 @@ PacketInfo PacketZZ::getPacketInfo() const { PacketInfo info{ .acl_permission = ACLRole::Permission::NONE, - .min_args = 0, + .min_args = 2, .header = "ZZ"}; return info; } @@ -29,10 +29,14 @@ void PacketZZ::handlePacket(AreaData *area, AOClient &client) const QString l_modcallNotice = "!!!MODCALL!!!\nArea: " + l_areaName + "\nCaller: " + l_name + "\n"; - if (m_content.size() > 0 && !m_content[0].isEmpty()) - l_modcallNotice.append("Reason: " + m_content[0]); - else - l_modcallNotice.append("No reason given."); + int target_id = m_content.at(1).toInt(); + if (target_id != -1) { + AOClient *target = client.getServer()->getClientByID(target_id); + if (target) { + l_modcallNotice.append("Regarding: " + target->name() + "\n"); + } + } + l_modcallNotice.append("Reason: " + m_content[0]); const QVector l_clients = client.getServer()->getClients(); for (AOClient *l_client : l_clients) { @@ -47,6 +51,15 @@ void PacketZZ::handlePacket(AreaData *area, AOClient &client) const l_name = client.character(); QString l_areaName = area->name(); - emit client.getServer()->modcallWebhookRequest(l_name, l_areaName, m_content.value(0), client.getServer()->getAreaBuffer(l_areaName)); + + QString webhook_reason = m_content.value(0); + if (target_id != -1) { + AOClient *target = client.getServer()->getClientByID(target_id); + if (target) { + webhook_reason.append(" (Regarding: " + target->name() + ")"); + } + } + + emit client.getServer()->modcallWebhookRequest(l_name, l_areaName, webhook_reason, client.getServer()->getAreaBuffer(l_areaName)); } } diff --git a/src/packet/packet_zz.h b/src/packet/packet_zz.h index 086a6013..1e61ef05 100644 --- a/src/packet/packet_zz.h +++ b/src/packet/packet_zz.h @@ -10,4 +10,5 @@ class PacketZZ : public AOPacket virtual PacketInfo getPacketInfo() const; virtual void handlePacket(AreaData *area, AOClient &client) const; }; + #endif diff --git a/src/playerstateobserver.cpp b/src/playerstateobserver.cpp index 64a82de0..49a84b8c 100644 --- a/src/playerstateobserver.cpp +++ b/src/playerstateobserver.cpp @@ -10,7 +10,7 @@ void PlayerStateObserver::registerClient(AOClient *client) { Q_ASSERT(!m_client_list.contains(client)); - PacketPLU packet(client->clientId(), PacketPLU::AddPlayerUpdate); + PacketPR packet(client->clientId(), PacketPR::ADD); sendToClientList(packet); m_client_list.append(client); @@ -20,20 +20,18 @@ void PlayerStateObserver::registerClient(AOClient *client) connect(client, &AOClient::characterNameChanged, this, &PlayerStateObserver::notifyCharacterNameChanged); connect(client, &AOClient::areaIdChanged, this, &PlayerStateObserver::notifyAreaIdChanged); - { // provide the player list to the new client - QList data_list; - for (AOClient *i_client : qAsConst(m_client_list)) { - PacketPL::PlayerData data; - data.id = i_client->clientId(); - data.name = i_client->name(); - data.character = i_client->character(); - data.character_name = i_client->characterName(); - data.area_id = i_client->areaId(); - data_list.append(data); - } - - PacketPL packet(data_list); - client->sendPacket(&packet); + QList packets; + for (AOClient *i_client : qAsConst(m_client_list)) { + packets.append(new PacketPR(i_client->clientId(), PacketPR::ADD)); + packets.append(new PacketPU(i_client->clientId(), PacketPU::NAME, i_client->name())); + packets.append(new PacketPU(i_client->clientId(), PacketPU::CHARACTER, i_client->character())); + packets.append(new PacketPU(i_client->clientId(), PacketPU::CHARACTER_NAME, i_client->characterName())); + packets.append(new PacketPU(i_client->clientId(), PacketPU::AREA_ID, i_client->areaId())); + } + + for (AOPacket *packet : qAsConst(packets)) { + client->sendPacket(packet); + delete packet; } } @@ -45,7 +43,7 @@ void PlayerStateObserver::unregisterClient(AOClient *client) m_client_list.removeAll(client); - PacketPLU packet(client->clientId(), PacketPLU::RemovePlayerUpdate); + PacketPR packet(client->clientId(), PacketPR::REMOVE); sendToClientList(packet); } @@ -58,24 +56,20 @@ void PlayerStateObserver::sendToClientList(const AOPacket &packet) void PlayerStateObserver::notifyNameChanged(const QString &name) { - qDebug() << "PlayerStateObserver::notifyNameChanged" << qobject_cast(sender())->clientId() << name; - sendToClientList(PacketPU(qobject_cast(sender())->clientId(), PacketPU::NameData, name)); + sendToClientList(PacketPU(qobject_cast(sender())->clientId(), PacketPU::NAME, name)); } void PlayerStateObserver::notifyCharacterChanged(const QString &character) { - qDebug() << "PlayerStateObserver::notifyCharacterChanged" << qobject_cast(sender())->clientId() << character; - sendToClientList(PacketPU(qobject_cast(sender())->clientId(), PacketPU::CharacterData, character)); + sendToClientList(PacketPU(qobject_cast(sender())->clientId(), PacketPU::CHARACTER, character)); } void PlayerStateObserver::notifyCharacterNameChanged(const QString &characterName) { - qDebug() << "PlayerStateObserver::notifyCharacterNameChanged" << qobject_cast(sender())->clientId() << characterName; - sendToClientList(PacketPU(qobject_cast(sender())->clientId(), PacketPU::CharacterNameData, characterName)); + sendToClientList(PacketPU(qobject_cast(sender())->clientId(), PacketPU::CHARACTER_NAME, characterName)); } void PlayerStateObserver::notifyAreaIdChanged(int areaId) { - qDebug() << "PlayerStateObserver::notifyAreaIdChanged" << qobject_cast(sender())->clientId() << areaId; - sendToClientList(PacketPU(qobject_cast(sender())->clientId(), PacketPU::AreaIdData, areaId)); + sendToClientList(PacketPU(qobject_cast(sender())->clientId(), PacketPU::AREA_ID, areaId)); } diff --git a/src/playerstateobserver.h b/src/playerstateobserver.h index 7cb8f969..425b9bd9 100644 --- a/src/playerstateobserver.h +++ b/src/playerstateobserver.h @@ -1,7 +1,8 @@ #pragma once +#include "akashidefs.h" #include "aoclient.h" -#include "packet/packet_pl.h" +#include "packet/packet_pr.h" #include #include diff --git a/src/server.cpp b/src/server.cpp index 3227cdb6..667712d3 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -184,7 +184,7 @@ void Server::clientConnected() ban_duration = QDateTime::fromSecsSinceEpoch(ban.second.time).addSecs(ban.second.duration).toString("MM/dd/yyyy, hh:mm"); } else { - ban_duration = "The heat death of the universe."; + ban_duration = "Permanently."; } AOPacket *ban_reason = PacketFactory::createPacket("BD", {"Reason: " + ban.second.reason + "\nBan ID: " + QString::number(ban.second.id) + "\nUntil: " + ban_duration}); socket->sendTextMessage(ban_reason->toUtf8()); diff --git a/tests/unittest_aopacket/tst_unittest_aopacket.cpp b/tests/unittest_aopacket/tst_unittest_aopacket.cpp index dceea969..bcbb6d79 100644 --- a/tests/unittest_aopacket/tst_unittest_aopacket.cpp +++ b/tests/unittest_aopacket/tst_unittest_aopacket.cpp @@ -116,7 +116,7 @@ void Packet::createPacketSubclass_data() << 7; QTest::newRow("ZZ") << "ZZ#" << "ZZ" - << 0; + << 2; } void Packet::createPacketSubclass()