diff --git a/config.cpp b/config.cpp new file mode 100644 index 0000000..c109ee3 --- /dev/null +++ b/config.cpp @@ -0,0 +1,166 @@ +/* +This file is part of IRCaBot. +IRCaBot is IRC logger with features. +Source code: https://notabug.org/acetone/ircabot. +Copyright (C) 2023, acetone. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#include "config.h" +#include "logger.h" + +#include +#include +#include +#include +#include + +constexpr const char CFG_LOG_LEVEL[] = "logLevel"; +constexpr const char CFG_LOG_FILE[] = "logFile"; +constexpr const char CFG_LOG_FILE_DATE_FORMAT[] = "logFileDateFormat"; +constexpr const char CFG_WORKING_DIRECTORY[] = "workingDirectory"; + +constexpr const char CFG_WEBUI[] = "webUI"; +constexpr const char CFG_WEBUI_ADDRESS[] = "address"; +constexpr const char CFG_WEBUI_PORT[] = "port"; +constexpr const char CFG_WEBUI_THREADS[] = "threads"; + +constexpr const char CFG_NETWORKS[] = "networks"; +constexpr const char CFG_NETWORK_NETWORKNAME[] = "networkName"; +constexpr const char CFG_NETWORK_NICKNAME[] = "nickname"; +constexpr const char CFG_NETWORK_PASSWORD[] = "password"; +constexpr const char CFG_NETWORK_IDENTIFY_FMT[] = "identifyFormat"; +constexpr const char CFG_NETWORK_HOST[] = "host"; +constexpr const char CFG_NETWORK_PORT[] = "port"; +constexpr const char CFG_NETWORK_SSL[] = "ssl"; +constexpr const char CFG_NETWORK_IDENT[] = "ident"; +constexpr const char CFG_NETWORK_REAL_NAME[] = "realName"; +constexpr const char CFG_NETWORK_AUTORECONNECT[] = "autoReconnect"; +constexpr const char CFG_NETWORK_VOICEGATE[] = "voiceGate"; +constexpr const char CFG_NETWORK_CHANNELS[] = "channels"; + +QString Config::m_configurationFilePath; +QString Config::m_logFilePath; +QString Config::m_logFileDateFormat = "yyyy-MM-dd hh:mm:ss"; + +QString Config::m_workingDirectory = ""; + +QString Config::m_webUiAddress; +quint16 Config::m_webUiPort; +uint Config::m_webUiThreads; + +QList Config::m_networks; + +bool Config::initFromFile(QString *errorString) +{ + QFile file( configurationFilePath() ); + if (not file.open(QIODevice::ReadOnly)) + { + if (errorString) *errorString = "Can't open file"; + + return false; + } + + QJsonParseError jerr; + QJsonObject jcfg = QJsonDocument::fromJson(file.readAll(), &jerr).object(); + file.close(); + + if (jerr.error != QJsonParseError::NoError) + { + if (errorString) *errorString = "Invalid JSON"; + + return false; + } + + return initFromJson(jcfg, errorString); +} + +bool Config::initFromJson(const QJsonObject &config, QString* errorString) +{ + logger::level = logger::levelEnum(config.value(CFG_LOG_LEVEL).toString()); + + m_logFilePath = config.value(CFG_LOG_FILE).toString(); + + m_workingDirectory = config.value(CFG_WORKING_DIRECTORY).toString(); + + QString buffer = config.value(CFG_LOG_FILE_DATE_FORMAT).toString(); + if (not buffer.isEmpty()) + { + m_logFileDateFormat = buffer; + } + + QJsonObject webUi = config.value(CFG_WEBUI).toObject(); + m_webUiAddress = webUi.value(CFG_WEBUI_ADDRESS).toString("127.0.0.1"); + m_webUiPort = webUi.value(CFG_WEBUI_PORT) .toInt(7666); + m_webUiThreads = webUi.value(CFG_WEBUI_THREADS).toInt(-1); // if <1, then system number + + QJsonArray jnetworks = config.value(CFG_NETWORKS).toArray(); + if (jnetworks.isEmpty()) + { + if (errorString) *errorString = "Networks array is undefined"; + + return false; + } + + uint unnamedNetworkCounter = 0; + for (const auto& jnet: jnetworks) + { + auto jnetobj = jnet.toObject(); + if (jnetobj.isEmpty()) continue; + + Network network; + + network.networkName = jnetobj.value(CFG_NETWORK_NETWORKNAME) .toString("Unnamed-" + QString::number(unnamedNetworkCounter++)); + network.nickname = jnetobj.value(CFG_NETWORK_NICKNAME) .toString(info::NAME); + network.password = jnetobj.value(CFG_NETWORK_PASSWORD) .toString(); + network.identifyFormat = jnetobj.value(CFG_NETWORK_IDENTIFY_FMT) .toString("PRIVMSG NickServ identify $nickname $password"); // from libircclient/network.cpp + network.ident = jnetobj.value(CFG_NETWORK_IDENT) .toString(QString(info::NAME) + " " + QString(info::VERSION)); + network.host = jnetobj.value(CFG_NETWORK_HOST) .toString(); + network.realName = jnetobj.value(CFG_NETWORK_REAL_NAME) .toString(info::SOURCE_CODE); + network.autoReconnect = jnetobj.value(CFG_NETWORK_AUTORECONNECT) .toBool(true); + network.voiceGate = jnetobj.value(CFG_NETWORK_VOICEGATE) .toBool(true); + network.ssl = jnetobj.value(CFG_NETWORK_SSL) .toBool(false); + network.port = jnetobj.value(CFG_NETWORK_PORT) .toInt(network.ssl ? 6697 : 6667); + + QJsonArray jchannels = jnetobj.value(CFG_NETWORK_CHANNELS).toArray(); + if (jchannels.isEmpty()) + { + if (errorString) *errorString = "No channels defined for " + network.networkName; + + return false; + } + for (const auto& jchan: jchannels) + { + QString channel = jchan.toString(); + channel.remove(' '); + if (channel.isEmpty()) continue; + if (not channel.startsWith('#')) + { + channel.push_front('#'); + } + network.channels.push_back(channel); + } + if (network.channels.isEmpty()) + { + if (errorString) *errorString = "No valid channels defined for " + network.networkName; + + return false; + } + + m_networks.push_back(network); + } + + return true; +} diff --git a/config.h b/config.h new file mode 100644 index 0000000..8d8e223 --- /dev/null +++ b/config.h @@ -0,0 +1,80 @@ +/* +This file is part of IRCaBot. +IRCaBot is IRC logger with features. +Source code: https://notabug.org/acetone/ircabot. +Copyright (C) 2023, acetone. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#pragma once + +#include "versioninformation.h" + +#include +#include + +class QJsonObject; + +class Config +{ +public: + Config() = delete; + + struct Network + { + // default values defined in initFromJson() + QString networkName; + QString host; + quint16 port; + bool ssl; + QString nickname; + QString password; + QString identifyFormat; + QString ident; + QString realName; + QStringList channels; + bool autoReconnect; + bool voiceGate; + }; + + static void setConfigurationFilePath(const QString& path) { m_configurationFilePath = path; } + static bool initFromFile(QString* errorString = nullptr); + static bool initFromJson(const QJsonObject& config, QString* errorString = nullptr); + + static const QString& configurationFilePath() { return m_configurationFilePath; } + static const QString& logFilePath() { return m_logFilePath; } + static const QString& logFileDateFormat() { return m_logFileDateFormat; } + + static const QString& webUiAddress() { return m_webUiAddress; } + static quint16 webUiPort() { return m_webUiPort; } + static int webUiThreads() { return m_webUiThreads; } + + static const QString& workingDirectory() { return m_workingDirectory; } + + static const QList& networks() { return m_networks; } + +private: + static QString m_configurationFilePath; + static QString m_logFilePath; + static QString m_logFileDateFormat; + static QString m_workingDirectory; + + static QString m_webUiAddress; + static quint16 m_webUiPort; + static uint m_webUiThreads; + + static QList m_networks; +}; +