
* Set default properly If this slight hack is not done, Akashi may load an empty color code, causing Discord to reject the Webhook due to an empty value.
624 lines
18 KiB
C++
624 lines
18 KiB
C++
//////////////////////////////////////////////////////////////////////////////////////
|
|
// akashi - a server for Attorney Online 2 //
|
|
// Copyright (C) 2020 scatterflower //
|
|
// //
|
|
// This program is free software: you can redistribute it and/or modify //
|
|
// it under the terms of the GNU Affero General Public License as //
|
|
// published by the Free Software Foundation, either version 3 of the //
|
|
// License, or (at your option) any later version. //
|
|
// //
|
|
// This program is distributed in the hope that it will be useful, //
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
|
// GNU Affero General Public License for more details. //
|
|
// //
|
|
// You should have received a copy of the GNU Affero General Public License //
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>. //
|
|
//////////////////////////////////////////////////////////////////////////////////////
|
|
#include "include/config_manager.h"
|
|
|
|
#include <include/config_manager.h>
|
|
|
|
QSettings* ConfigManager::m_settings = new QSettings("config/config.ini", QSettings::IniFormat);
|
|
QSettings* ConfigManager::m_discord = new QSettings("config/discord.ini", QSettings::IniFormat);
|
|
QSettings* ConfigManager::m_areas = new QSettings("config/areas.ini", QSettings::IniFormat);
|
|
QSettings* ConfigManager::m_logtext = new QSettings("config/text/logtext.ini", QSettings::IniFormat);
|
|
ConfigManager::CommandSettings* ConfigManager::m_commands = new CommandSettings();
|
|
QElapsedTimer* ConfigManager::m_uptimeTimer = new QElapsedTimer;
|
|
MusicList* ConfigManager::m_musicList = new MusicList;
|
|
QHash<QString,ConfigManager::help>* ConfigManager::m_commands_help = new QHash<QString,ConfigManager::help>;
|
|
QStringList* ConfigManager::m_ordered_list = new QStringList;
|
|
|
|
bool ConfigManager::verifyServerConfig()
|
|
{
|
|
// Verify directories
|
|
QStringList l_directories{"config/", "config/text/"};
|
|
for (const QString &l_directory : l_directories) {
|
|
if (!dirExists(QFileInfo(l_directory))) {
|
|
qCritical() << l_directory + " does not exist!";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Verify config files
|
|
QStringList l_config_files{"config/config.ini", "config/areas.ini", "config/backgrounds.txt", "config/characters.txt", "config/music.json",
|
|
"config/discord.ini", "config/text/8ball.txt", "config/text/gimp.txt", "config/text/praise.txt",
|
|
"config/text/reprimands.txt","config/text/commandhelp.json","config/text/cdns.txt"};
|
|
for (const QString &l_file : l_config_files) {
|
|
if (!fileExists(QFileInfo(l_file))) {
|
|
qCritical() << l_file + " does not exist!";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Verify areas
|
|
QSettings l_areas_ini("config/areas.ini", QSettings::IniFormat);
|
|
l_areas_ini.setIniCodec("UTF-8");
|
|
if (l_areas_ini.childGroups().length() < 1) {
|
|
qCritical() << "areas.ini is invalid!";
|
|
return false;
|
|
}
|
|
|
|
// Verify config settings
|
|
m_settings->beginGroup("Options");
|
|
bool ok;
|
|
m_settings->value("ms_port", 27016).toInt(&ok);
|
|
if (!ok) {
|
|
qCritical("ms_port is not a valid port!");
|
|
return false;
|
|
}
|
|
m_settings->value("port", 27016).toInt(&ok);
|
|
if (!ok) {
|
|
qCritical("port is not a valid port!");
|
|
return false;
|
|
}
|
|
bool web_ao = m_settings->value("webao_enable", false).toBool();
|
|
if (!web_ao) {
|
|
m_settings->setValue("webao_port", -1);
|
|
}
|
|
else {
|
|
m_settings->value("webao_port", 27017).toInt(&ok);
|
|
if (!ok) {
|
|
qCritical("webao_port is not a valid port!");
|
|
return false;
|
|
}
|
|
}
|
|
QString l_auth = m_settings->value("auth", "simple").toString().toLower();
|
|
if (!(l_auth == "simple" || l_auth == "advanced")) {
|
|
qCritical("auth is not a valid auth type!");
|
|
return false;
|
|
}
|
|
m_settings->endGroup();
|
|
m_commands->magic_8ball = (loadConfigFile("8ball"));
|
|
m_commands->praises = (loadConfigFile("praise"));
|
|
m_commands->reprimands = (loadConfigFile("reprimands"));
|
|
m_commands->gimps = (loadConfigFile("gimp"));
|
|
m_commands->cdns = (loadConfigFile("cdns"));
|
|
|
|
m_uptimeTimer->start();
|
|
|
|
return true;
|
|
}
|
|
|
|
QString ConfigManager::bindIP()
|
|
{
|
|
return m_settings->value("Options/bind_ip","all").toString();
|
|
}
|
|
|
|
QStringList ConfigManager::charlist()
|
|
{
|
|
QStringList l_charlist;
|
|
QFile l_file("config/characters.txt");
|
|
l_file.open(QIODevice::ReadOnly | QIODevice::Text);
|
|
while (!l_file.atEnd()) {
|
|
l_charlist.append(l_file.readLine().trimmed());
|
|
}
|
|
l_file.close();
|
|
|
|
return l_charlist;
|
|
}
|
|
|
|
QStringList ConfigManager::backgrounds()
|
|
{
|
|
QStringList l_backgrounds;
|
|
QFile l_file("config/backgrounds.txt");
|
|
l_file.open(QIODevice::ReadOnly | QIODevice::Text);
|
|
while (!l_file.atEnd()) {
|
|
l_backgrounds.append(l_file.readLine().trimmed());
|
|
}
|
|
l_file.close();
|
|
|
|
return l_backgrounds;
|
|
}
|
|
|
|
MusicList ConfigManager::musiclist()
|
|
{
|
|
QFile l_music_json("config/music.json");
|
|
l_music_json.open(QIODevice::ReadOnly | QIODevice::Text);
|
|
|
|
QJsonParseError l_error;
|
|
QJsonDocument l_music_list_json = QJsonDocument::fromJson(l_music_json.readAll(), &l_error);
|
|
if (!(l_error.error == QJsonParseError::NoError)) { //Non-Terminating error.
|
|
qWarning() << "Unable to load musiclist. The following error was encounted : " + l_error.errorString();
|
|
return QMap<QString,QPair<QString,int>>{}; //Server can still run without music.
|
|
}
|
|
|
|
// Akashi expects the musiclist to be contained in a JSON array, even if its only a single category.
|
|
QJsonArray l_Json_root_array = l_music_list_json.array();
|
|
QJsonObject l_child_obj;
|
|
QJsonArray l_child_array;
|
|
for (int i = 0; i <= l_Json_root_array.size() -1; i++){ //Iterate trough entire JSON file to assemble musiclist
|
|
l_child_obj = l_Json_root_array.at(i).toObject();
|
|
|
|
//Technically not a requirement, but neat for organisation.
|
|
QString l_category_name = l_child_obj["category"].toString();
|
|
if (!l_category_name.isEmpty()) {
|
|
m_musicList->insert(l_category_name,{l_category_name,0});
|
|
m_ordered_list->append(l_category_name);
|
|
}
|
|
else {
|
|
qWarning() << "Category name not set. This may cause the musiclist to be displayed incorrectly.";
|
|
}
|
|
|
|
l_child_array = l_child_obj["songs"].toArray();
|
|
for (int i = 0; i <= l_child_array.size() -1; i++){ // Inner for loop because a category can contain multiple songs.
|
|
QJsonObject l_song_obj = l_child_array.at(i).toObject();
|
|
QString l_song_name = l_song_obj["name"].toString();
|
|
QString l_real_name = l_song_obj["realname"].toString();
|
|
if (l_real_name.isEmpty()) {
|
|
l_real_name = l_song_name;
|
|
}
|
|
int l_song_duration = l_song_obj["length"].toVariant().toInt();
|
|
m_musicList->insert(l_song_name,{l_real_name,l_song_duration});
|
|
m_ordered_list->append(l_song_name);
|
|
}
|
|
}
|
|
l_music_json.close();
|
|
|
|
return *m_musicList;
|
|
}
|
|
|
|
QStringList ConfigManager::ordered_songs()
|
|
{
|
|
return *m_ordered_list;
|
|
}
|
|
|
|
void ConfigManager::loadCommandHelp()
|
|
{
|
|
QFile l_help_json("config/text/commandhelp.json");
|
|
l_help_json.open(QIODevice::ReadOnly | QIODevice::Text);
|
|
|
|
QJsonParseError l_error;
|
|
QJsonDocument l_help_list_json = QJsonDocument::fromJson(l_help_json.readAll(), &l_error);
|
|
if (!(l_error.error == QJsonParseError::NoError)) { //Non-Terminating error.
|
|
qWarning() << "Unable to load help information. The following error occurred: " + l_error.errorString();
|
|
}
|
|
|
|
// Akashi expects the helpfile to contain multiple entires, so it always checks for an array first.
|
|
QJsonArray l_Json_root_array = l_help_list_json.array();
|
|
QJsonObject l_child_obj;
|
|
|
|
for (int i = 0; i <= l_Json_root_array.size() -1; i++){
|
|
l_child_obj = l_Json_root_array.at(i).toObject();
|
|
QString l_name = l_child_obj["name"].toString();
|
|
QString l_usage = l_child_obj["usage"].toString();
|
|
QString l_text = l_child_obj["text"].toString();
|
|
|
|
if (!l_name.isEmpty()) {
|
|
help l_help_information;
|
|
l_help_information.usage = l_usage;
|
|
l_help_information.text = l_text;
|
|
|
|
m_commands_help->insert(l_name,l_help_information);
|
|
}
|
|
}
|
|
}
|
|
|
|
QSettings* ConfigManager::areaData()
|
|
{
|
|
return m_areas;
|
|
}
|
|
|
|
QStringList ConfigManager::sanitizedAreaNames()
|
|
{
|
|
QStringList l_area_names = m_areas->childGroups(); // invisibly does a lexicographical sort, because Qt is great like that
|
|
std::sort(l_area_names.begin(), l_area_names.end(), [] (const QString &a, const QString &b) {return a.split(":")[0].toInt() < b.split(":")[0].toInt();});
|
|
QStringList l_sanitized_area_names;
|
|
for (const QString &areaName : qAsConst(l_area_names)) {
|
|
QStringList l_nameSplit = areaName.split(":");
|
|
l_nameSplit.removeFirst();
|
|
QString l_area_name_sanitized = l_nameSplit.join(":");
|
|
l_sanitized_area_names.append(l_area_name_sanitized);
|
|
}
|
|
return l_sanitized_area_names;
|
|
}
|
|
|
|
QStringList ConfigManager::rawAreaNames()
|
|
{
|
|
return m_areas->childGroups();
|
|
}
|
|
|
|
QStringList ConfigManager::iprangeBans()
|
|
{
|
|
QStringList l_iprange_bans;
|
|
QFile l_file("config/iprange_bans.txt");
|
|
l_file.open(QIODevice::ReadOnly | QIODevice::Text);
|
|
while (!(l_file.atEnd())) {
|
|
l_iprange_bans.append(l_file.readLine().trimmed());
|
|
}
|
|
l_file.close();
|
|
return l_iprange_bans;
|
|
}
|
|
|
|
void ConfigManager::reloadSettings()
|
|
{
|
|
m_settings->sync();
|
|
m_discord->sync();
|
|
m_logtext->sync();
|
|
}
|
|
|
|
QStringList ConfigManager::loadConfigFile(const QString filename)
|
|
{
|
|
QStringList stringlist;
|
|
QFile l_file("config/text/" + filename + ".txt");
|
|
l_file.open(QIODevice::ReadOnly | QIODevice::Text);
|
|
while (!(l_file.atEnd())) {
|
|
stringlist.append(l_file.readLine().trimmed());
|
|
}
|
|
l_file.close();
|
|
return stringlist;
|
|
}
|
|
|
|
int ConfigManager::maxPlayers()
|
|
{
|
|
bool ok;
|
|
int l_players = m_settings->value("Options/max_players", 100).toInt(&ok);
|
|
if (!ok) {
|
|
qWarning("max_players is not an int!");
|
|
l_players = 100;
|
|
}
|
|
return l_players;
|
|
}
|
|
|
|
int ConfigManager::serverPort()
|
|
{
|
|
return m_settings->value("Options/port", 27016).toInt();
|
|
}
|
|
|
|
QString ConfigManager::serverDescription()
|
|
{
|
|
return m_settings->value("Options/server_description", "This is my flashy new server!").toString();
|
|
}
|
|
|
|
QString ConfigManager::serverName()
|
|
{
|
|
return m_settings->value("Options/server_name", "An Unnamed Server").toString();
|
|
}
|
|
|
|
QString ConfigManager::motd()
|
|
{
|
|
return m_settings->value("Options/motd", "MOTD not set").toString();
|
|
}
|
|
|
|
bool ConfigManager::webaoEnabled()
|
|
{
|
|
return m_settings->value("Options/webao_enable", false).toBool();
|
|
}
|
|
|
|
int ConfigManager::webaoPort()
|
|
{
|
|
return m_settings->value("Options/webao_port", 27017).toInt();
|
|
}
|
|
|
|
DataTypes::AuthType ConfigManager::authType()
|
|
{
|
|
QString l_auth = m_settings->value("Options/auth", "simple").toString().toUpper();
|
|
return toDataType<DataTypes::AuthType>(l_auth);
|
|
}
|
|
|
|
QString ConfigManager::modpass()
|
|
{
|
|
return m_settings->value("Options/modpass", "changeme").toString();
|
|
}
|
|
|
|
int ConfigManager::logBuffer()
|
|
{
|
|
bool ok;
|
|
int l_buffer = m_settings->value("Options/logbuffer", 500).toInt(&ok);
|
|
if (!ok) {
|
|
qWarning("logbuffer is not an int!");
|
|
l_buffer = 500;
|
|
}
|
|
return l_buffer;
|
|
}
|
|
|
|
DataTypes::LogType ConfigManager::loggingType()
|
|
{
|
|
QString l_log = m_settings->value("Options/logging", "modcall").toString().toUpper();
|
|
return toDataType<DataTypes::LogType>(l_log);
|
|
}
|
|
|
|
int ConfigManager::maxStatements()
|
|
{
|
|
bool ok;
|
|
int l_max = m_settings->value("Options/maximum_statements", 10).toInt(&ok);
|
|
if (!ok) {
|
|
qWarning("maximum_statements is not an int!");
|
|
l_max = 10;
|
|
}
|
|
return l_max;
|
|
}
|
|
int ConfigManager::multiClientLimit()
|
|
{
|
|
bool ok;
|
|
int l_limit = m_settings->value("Options/multiclient_limit", 15).toInt(&ok);
|
|
if (!ok) {
|
|
qWarning("multiclient_limit is not an int!");
|
|
l_limit = 15;
|
|
}
|
|
return l_limit;
|
|
}
|
|
|
|
int ConfigManager::maxCharacters()
|
|
{
|
|
bool ok;
|
|
int l_max = m_settings->value("Options/maximum_characters", 256).toInt(&ok);
|
|
if (!ok) {
|
|
qWarning("maximum_characters is not an int!");
|
|
l_max = 256;
|
|
}
|
|
return l_max;
|
|
}
|
|
|
|
int ConfigManager::messageFloodguard()
|
|
{
|
|
bool ok;
|
|
int l_flood = m_settings->value("Options/message_floodguard", 250).toInt(&ok);
|
|
if (!ok) {
|
|
qWarning("message_floodguard is not an int!");
|
|
l_flood = 250;
|
|
}
|
|
return l_flood;
|
|
}
|
|
|
|
QUrl ConfigManager::assetUrl()
|
|
{
|
|
QByteArray l_url = m_settings->value("Options/asset_url", "").toString().toUtf8();
|
|
if (QUrl(l_url).isValid()) {
|
|
return QUrl(l_url);
|
|
}
|
|
else {
|
|
qWarning("asset_url is not a valid url!");
|
|
return QUrl(NULL);
|
|
}
|
|
}
|
|
|
|
int ConfigManager::diceMaxValue()
|
|
{
|
|
bool ok;
|
|
int l_value = m_settings->value("Dice/max_value", 100).toInt(&ok);
|
|
if (!ok) {
|
|
qWarning("max_value is not an int!");
|
|
l_value = 100;
|
|
}
|
|
return l_value;
|
|
}
|
|
|
|
int ConfigManager::diceMaxDice()
|
|
{
|
|
bool ok;
|
|
int l_dice = m_settings->value("Dice/max_dice", 100).toInt(&ok);
|
|
if (!ok) {
|
|
qWarning("max_dice is not an int!");
|
|
l_dice = 100;
|
|
}
|
|
return l_dice;
|
|
}
|
|
|
|
bool ConfigManager::discordWebhookEnabled()
|
|
{
|
|
return m_discord->value("Discord/webhook_enabled", false).toBool();
|
|
}
|
|
|
|
bool ConfigManager::discordModcallWebhookEnabled()
|
|
{
|
|
return m_discord->value("Discord/webhook_modcall_enabled", false).toBool();
|
|
}
|
|
|
|
QString ConfigManager::discordModcallWebhookUrl()
|
|
{
|
|
return m_discord->value("Discord/webhook_modcall_url", "").toString();
|
|
}
|
|
|
|
QString ConfigManager::discordModcallWebhookContent()
|
|
{
|
|
return m_discord->value("Discord/webhook_modcall_content", "").toString();
|
|
}
|
|
|
|
bool ConfigManager::discordModcallWebhookSendFile()
|
|
{
|
|
return m_discord->value("Discord/webhook_modcall_sendfile", false).toBool();
|
|
}
|
|
|
|
bool ConfigManager::discordBanWebhookEnabled()
|
|
{
|
|
return m_discord->value("Discord/webhook_ban_enabled", false).toBool();
|
|
}
|
|
|
|
QString ConfigManager::discordBanWebhookUrl()
|
|
{
|
|
return m_discord->value("Discord/webhook_ban_url", "").toString();
|
|
}
|
|
|
|
bool ConfigManager::discordUptimeEnabled()
|
|
{
|
|
return m_discord->value("Discord/webhook_uptime_enabled","false").toBool();
|
|
}
|
|
|
|
int ConfigManager::discordUptimeTime()
|
|
{
|
|
bool ok;
|
|
int l_aliveTime = m_discord->value("Discord/webhook_uptime_time","60").toInt(&ok);
|
|
if (!ok) {
|
|
qWarning("alive_time is not an int");
|
|
l_aliveTime = 60;
|
|
}
|
|
return l_aliveTime;
|
|
}
|
|
|
|
QString ConfigManager::discordUptimeWebhookUrl()
|
|
{
|
|
return m_discord->value("Discord/webhook_uptime_url", "").toString();
|
|
}
|
|
|
|
QString ConfigManager::discordWebhookColor()
|
|
{
|
|
const QString l_default_color = "13312842";
|
|
QString l_color = m_discord->value("Discord/webhook_color", l_default_color).toString();
|
|
if (l_color.isEmpty()) {
|
|
return l_default_color;
|
|
}
|
|
else {
|
|
return l_color;
|
|
}
|
|
}
|
|
|
|
bool ConfigManager::passwordRequirements()
|
|
{
|
|
return m_settings->value("Password/password_requirements", true).toBool();
|
|
}
|
|
|
|
int ConfigManager::passwordMinLength()
|
|
{
|
|
bool ok;
|
|
int l_min = m_settings->value("Password/pass_min_length", 8).toInt(&ok);
|
|
if (!ok) {
|
|
qWarning("pass_min_length is not an int!");
|
|
l_min = 8;
|
|
}
|
|
return l_min;
|
|
}
|
|
|
|
int ConfigManager::passwordMaxLength()
|
|
{
|
|
bool ok;
|
|
int l_max = m_settings->value("Password/pass_max_length", 0).toInt(&ok);
|
|
if (!ok) {
|
|
qWarning("pass_max_length is not an int!");
|
|
l_max = 0;
|
|
}
|
|
return l_max;
|
|
}
|
|
|
|
bool ConfigManager::passwordRequireMixCase()
|
|
{
|
|
return m_settings->value("Password/pass_required_mix_case", true).toBool();
|
|
}
|
|
|
|
bool ConfigManager::passwordRequireNumbers()
|
|
{
|
|
return m_settings->value("Password/pass_required_numbers", true).toBool();
|
|
}
|
|
|
|
bool ConfigManager::passwordRequireSpecialCharacters()
|
|
{
|
|
return m_settings->value("Password/pass_required_special", true).toBool();
|
|
}
|
|
|
|
bool ConfigManager::passwordCanContainUsername()
|
|
{
|
|
return m_settings->value("Password/pass_can_contain_username", false).toBool();
|
|
}
|
|
|
|
QString ConfigManager::LogText(QString f_logtype)
|
|
{
|
|
return m_logtext->value("LogConfiguration/" + f_logtype,"").toString();
|
|
}
|
|
|
|
int ConfigManager::afkTimeout()
|
|
{
|
|
bool ok;
|
|
int l_afk = m_settings->value("Options/afk_timeout", 300).toInt(&ok);
|
|
if (!ok) {
|
|
qWarning("afk_timeout is not an int!");
|
|
l_afk = 300;
|
|
}
|
|
return l_afk;
|
|
}
|
|
|
|
void ConfigManager::setAuthType(const DataTypes::AuthType f_auth)
|
|
{
|
|
m_settings->setValue("Options/auth", fromDataType<DataTypes::AuthType>(f_auth).toLower());
|
|
}
|
|
|
|
QStringList ConfigManager::magic8BallAnswers()
|
|
{
|
|
return m_commands->magic_8ball;
|
|
}
|
|
|
|
QStringList ConfigManager::praiseList()
|
|
{
|
|
return m_commands->praises;
|
|
}
|
|
|
|
QStringList ConfigManager::reprimandsList()
|
|
{
|
|
return m_commands->reprimands;
|
|
}
|
|
|
|
QStringList ConfigManager::gimpList()
|
|
{
|
|
return m_commands->gimps;
|
|
}
|
|
|
|
QStringList ConfigManager::cdnList()
|
|
{
|
|
return m_commands->cdns;
|
|
}
|
|
|
|
bool ConfigManager::advertiseServer()
|
|
{
|
|
return m_settings->value("Advertiser/advertise","true").toBool();
|
|
}
|
|
|
|
bool ConfigManager::advertiserDebug()
|
|
{
|
|
return m_settings->value("Advertiser/debug","true").toBool();
|
|
}
|
|
|
|
QUrl ConfigManager::advertiserIP()
|
|
{
|
|
qDebug() << m_settings->value("Advertiser/ms_ip","").toUrl();
|
|
return m_settings->value("Advertiser/ms_ip","").toUrl();
|
|
}
|
|
|
|
QString ConfigManager::advertiserHostname()
|
|
{
|
|
return m_settings->value("Advertiser/hostname","").toString();
|
|
}
|
|
|
|
qint64 ConfigManager::uptime()
|
|
{
|
|
return m_uptimeTimer->elapsed();
|
|
}
|
|
|
|
ConfigManager::help ConfigManager::commandHelp(QString f_command_name)
|
|
{
|
|
return m_commands_help->value(f_command_name);
|
|
}
|
|
|
|
void ConfigManager::setMotd(const QString f_motd)
|
|
{
|
|
m_settings->setValue("Options/motd", f_motd);
|
|
}
|
|
|
|
bool ConfigManager::fileExists(const QFileInfo &f_file)
|
|
{
|
|
return (f_file.exists() && f_file.isFile());
|
|
}
|
|
|
|
bool ConfigManager::dirExists(const QFileInfo &f_dir)
|
|
{
|
|
return (f_dir.exists() && f_dir.isDir());
|
|
}
|