From be04b68a0f10891b81c07cdda204a9abc0ac56a7 Mon Sep 17 00:00:00 2001 From: Manuel Nickschas Date: Sat, 8 Oct 2016 00:40:46 +0200 Subject: [PATCH] dcc: Add persistent settings for core-side DCC This introduces a new syncable object DccConfig that holds core-side DCC settings, such as the network configuration. The configuration is persisted as a per-user setting in the database. The CoreSession's DccConfig instance is synced to connected clients and accessible via the Client singleton. --- src/client/client.cpp | 12 ++- src/client/client.h | 3 + src/common/CMakeLists.txt | 1 + src/common/dccconfig.cpp | 198 +++++++++++++++++++++++++++++++++++++ src/common/dccconfig.h | 151 ++++++++++++++++++++++++++++ src/core/CMakeLists.txt | 1 + src/core/coredccconfig.cpp | 46 +++++++++ src/core/coredccconfig.h | 51 ++++++++++ src/core/coresession.cpp | 3 + src/core/coresession.h | 3 + 10 files changed, 468 insertions(+), 1 deletion(-) create mode 100644 src/common/dccconfig.cpp create mode 100644 src/common/dccconfig.h create mode 100644 src/core/coredccconfig.cpp create mode 100644 src/core/coredccconfig.h diff --git a/src/client/client.cpp b/src/client/client.cpp index 91165418..5319a9a6 100644 --- a/src/client/client.cpp +++ b/src/client/client.cpp @@ -38,6 +38,7 @@ #include "clientuserinputhandler.h" #include "coreaccountmodel.h" #include "coreconnection.h" +#include "dccconfig.h" #include "ircchannel.h" #include "ircuser.h" #include "message.h" @@ -101,6 +102,7 @@ Client::Client(QObject *parent) _backlogManager(new ClientBacklogManager(this)), _bufferViewManager(0), _bufferViewOverlay(new BufferViewOverlay(this)), + _dccConfig(0), _ircListHelper(new ClientIrcListHelper(this)), _inputHandler(0), _networkConfig(0), @@ -414,9 +416,12 @@ void Client::setSyncedToCore() _ignoreListManager = new ClientIgnoreListManager(this); p->synchronize(ignoreListManager()); - // create TransferManager if core supports it + // create TransferManager and DccConfig if core supports them + Q_ASSERT(!_dccConfig); Q_ASSERT(!_transferManager); if (coreFeatures() & Quassel::DccFileTransfer) { + _dccConfig = new DccConfig(this); + p->synchronize(dccConfig()); _transferManager = new ClientTransferManager(this); _transferModel->setManager(_transferManager); p->synchronize(transferManager()); @@ -498,6 +503,11 @@ void Client::setDisconnectedFromCore() _transferManager = nullptr; } + if (_dccConfig) { + _dccConfig->deleteLater(); + _dccConfig = nullptr; + } + // we probably don't want to save pending input for reconnect _userInputBuffer.clear(); diff --git a/src/client/client.h b/src/client/client.h index 98153527..ec5e9559 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -53,6 +53,7 @@ class ClientTransferManager; class ClientUserInputHandler; class CoreAccountModel; class CoreConnection; +class DccConfig; class IrcUser; class IrcChannel; class NetworkConfig; @@ -114,6 +115,7 @@ public: static inline ClientAliasManager *aliasManager() { return instance()->_aliasManager; } static inline ClientBacklogManager *backlogManager() { return instance()->_backlogManager; } + static inline DccConfig *dccConfig() { return instance()->_dccConfig; } static inline ClientIrcListHelper *ircListHelper() { return instance()->_ircListHelper; } static inline ClientBufferViewManager *bufferViewManager() { return instance()->_bufferViewManager; } static inline BufferViewOverlay *bufferViewOverlay() { return instance()->_bufferViewOverlay; } @@ -247,6 +249,7 @@ private: ClientBacklogManager *_backlogManager; ClientBufferViewManager *_bufferViewManager; BufferViewOverlay *_bufferViewOverlay; + DccConfig *_dccConfig; ClientIrcListHelper *_ircListHelper; ClientUserInputHandler *_inputHandler; NetworkConfig *_networkConfig; diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 56c562c6..a0227561 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -11,6 +11,7 @@ set(SOURCES bufferviewmanager.cpp compressor.cpp ctcpevent.cpp + dccconfig.cpp event.cpp eventmanager.cpp identity.cpp diff --git a/src/common/dccconfig.cpp b/src/common/dccconfig.cpp new file mode 100644 index 00000000..ce826b3a --- /dev/null +++ b/src/common/dccconfig.cpp @@ -0,0 +1,198 @@ +/*************************************************************************** + * Copyright (C) 2005-2016 by the Quassel Project * + * devel@quassel-irc.org * + * * + * 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 2 of the License, or * + * (at your option) version 3. * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#include "dccconfig.h" + +#include + +#include "types.h" + +INIT_SYNCABLE_OBJECT(DccConfig) + +DccConfig::DccConfig(QObject *parent) + : SyncableObject(parent) +{ + static auto regTypes = []() -> bool { + qRegisterMetaTypeStreamOperators("DccConfig::IpDetectionMode"); + qRegisterMetaTypeStreamOperators("DccConfig::PortSelectionMode"); + return true; + }(); + Q_UNUSED(regTypes); + + renameObject("DccConfig"); + setAllowClientUpdates(true); +} + + +DccConfig &DccConfig::operator=(const DccConfig &other) +{ + if (this == &other) + return *this; + + SyncableObject::operator=(other); + + static auto propCount = staticMetaObject.propertyCount(); + for (int i = 0; i < propCount; ++i) { + auto propName = staticMetaObject.property(i).name(); + setProperty(propName, other.property(propName)); + } + + return *this; +} + + +bool DccConfig::operator==(const DccConfig &other) +{ + // NOTE: We don't compare the SyncableObject attributes (isInitialized, clientUpdatesAllowed()) + static auto propCount = staticMetaObject.propertyCount(); + for (int i = 0; i < propCount; ++i) { + auto propName = staticMetaObject.property(i).name(); + if (QLatin1String(propName) == QLatin1String("objectName")) + continue; + if (QLatin1String(propName) == QLatin1String("outgoingIp")) { + // QVariant can't compare QHostAddress + if (property(propName).value() != other.property(propName).value()) + return false; + } + else if (property(propName) != other.property(propName)) + return false; + } + return true; +} + + +bool DccConfig::isDccEnabled() const +{ + return _dccEnabled; +} + + +void DccConfig::setDccEnabled(bool enabled) +{ + _dccEnabled = enabled; +} + + +QHostAddress DccConfig::outgoingIp() const +{ + return _outgoingIp; +} + + +void DccConfig::setOutgoingIp(const QHostAddress &outgoingIp) +{ + _outgoingIp = outgoingIp; +} + + +DccConfig::IpDetectionMode DccConfig::ipDetectionMode() const +{ + return _ipDetectionMode; +} + + +void DccConfig::setIpDetectionMode(DccConfig::IpDetectionMode detectionMode) +{ + _ipDetectionMode = detectionMode; +} + + +DccConfig::PortSelectionMode DccConfig::portSelectionMode() const +{ + return _portSelectionMode; +} + + +void DccConfig::setPortSelectionMode(DccConfig::PortSelectionMode portSelectionMode) +{ + _portSelectionMode = portSelectionMode; +} + + +quint16 DccConfig::minPort() const +{ + return _minPort; +} + + +void DccConfig::setMinPort(quint16 port) +{ + _minPort = port; +} + + +quint16 DccConfig::maxPort() const +{ + return _maxPort; +} + + +void DccConfig::setMaxPort(quint16 port) +{ + _maxPort = port; +} + + +int DccConfig::chunkSize() const +{ + return _chunkSize; +} + + +void DccConfig::setChunkSize(int chunkSize) +{ + _chunkSize = chunkSize; +} + + +int DccConfig::sendTimeout() const +{ + return _sendTimeout; +} + + +void DccConfig::setSendTimeout(int timeout) +{ + _sendTimeout = timeout; +} + + +bool DccConfig::usePassiveDcc() const +{ + return _usePassiveDcc; +} + + +void DccConfig::setUsePassiveDcc(bool use) +{ + _usePassiveDcc = use; +} + + +bool DccConfig::useFastSend() const +{ + return _useFastSend; +} + + +void DccConfig::setUseFastSend(bool use) +{ + _useFastSend = use; +} diff --git a/src/common/dccconfig.h b/src/common/dccconfig.h new file mode 100644 index 00000000..b4a34f84 --- /dev/null +++ b/src/common/dccconfig.h @@ -0,0 +1,151 @@ +/*************************************************************************** + * Copyright (C) 2005-2016 by the Quassel Project * + * devel@quassel-irc.org * + * * + * 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 2 of the License, or * + * (at your option) version 3. * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#pragma once + +#include + +#include "syncableobject.h" + +/** + * Class holding the core-side DCC configuration. + * + * @warning Equality and assignment operators are optimized for use in a settings page + * and do not cover all attributes! + */ +class DccConfig : public SyncableObject +{ + Q_OBJECT + SYNCABLE_OBJECT + + /// Whether DCC is enabled + Q_PROPERTY(bool dccEnabled READ isDccEnabled WRITE setDccEnabled) + /// The IP to use for outgoing traffic + Q_PROPERTY(QHostAddress outgoingIp READ outgoingIp WRITE setOutgoingIp) + /// The IP detection mode + Q_PROPERTY(DccConfig::IpDetectionMode ipDetectionMode READ ipDetectionMode WRITE setIpDetectionMode) + /// The port range selection mode + Q_PROPERTY(DccConfig::PortSelectionMode portSelectionMode READ portSelectionMode WRITE setPortSelectionMode) + /// Minimum port to use for incoming connections + Q_PROPERTY(quint16 minPort READ minPort WRITE setMinPort) + /// Maximum port to use for incoming connections + Q_PROPERTY(quint16 maxPort READ maxPort WRITE setMaxPort) + /// The chunk size to be used + Q_PROPERTY(int chunkSize READ chunkSize WRITE setChunkSize) + /// The timeout for DCC transfers + Q_PROPERTY(int sendTimeout READ sendTimeout WRITE setSendTimeout) + /// Whether passive (reverse) DCC should be used + Q_PROPERTY(bool usePassiveDcc READ usePassiveDcc WRITE setUsePassiveDcc) + /// Whether fast sending should be used + Q_PROPERTY(bool useFastSend READ useFastSend WRITE setUseFastSend) + +public: + /** + * Mode for detecting the outgoing IP + */ + enum class IpDetectionMode : quint8 { + Automatic, ///< Automatic detection (network socket or USERHOST) + Manual, ///< Manually specified IP + }; + Q_ENUMS(IpDetectionMode) + + /** + * Mode for selecting the port range for DCC + */ + enum class PortSelectionMode : quint8 { + Automatic, ///< Automatic port selection + Manual, ///< Manually specified port range + }; + Q_ENUMS(PortSelectionMode) + + /** + * Constructor. + * + * Initializes the object with useful default values. + * + * @param[in] parent QObject parent + */ + DccConfig(QObject *parent = nullptr); + + // see base class + const QMetaObject *syncMetaObject() const override { return &staticMetaObject; } + + /** + * Assignment operator. + * + * @note Only assigns properties relevant for config management! + * + * @param[in] other Right-hand side instance + * @returns The updated instance + */ + DccConfig &operator=(const DccConfig &other); + + /** + * Equality operator. + * + * @note Only compares properties relevant for config management! + * + * @param[in] other Right-hand side instance + * @returns Whether the two instances have equal properties + */ + bool operator==(const DccConfig &other); + + /// @name Getters + /// @{ + bool isDccEnabled() const; + QHostAddress outgoingIp() const; + IpDetectionMode ipDetectionMode() const; + PortSelectionMode portSelectionMode() const; + quint16 minPort() const; + quint16 maxPort() const; + int chunkSize() const; + int sendTimeout() const; + bool usePassiveDcc() const; + bool useFastSend() const; + /// @} + +public slots: + /// @name Setters + /// @{ + void setDccEnabled(bool enabled); + void setOutgoingIp(const QHostAddress &outgoingIp); + void setIpDetectionMode(DccConfig::IpDetectionMode ipDetectionMode); + void setPortSelectionMode(DccConfig::PortSelectionMode portSelectionMode); + void setMinPort(quint16 port); + void setMaxPort(quint16 port); + void setChunkSize(int chunkSize); + void setSendTimeout(int timeout); + void setUsePassiveDcc(bool use); + void setUseFastSend(bool use); + /// @} + +private: + // The given values are used as default for both initialization and settings + bool _dccEnabled {false}; + QHostAddress _outgoingIp {QHostAddress::LocalHost}; + IpDetectionMode _ipDetectionMode {IpDetectionMode::Automatic}; + PortSelectionMode _portSelectionMode {PortSelectionMode::Automatic}; + quint16 _minPort {1024}; + quint16 _maxPort {32767}; + int _chunkSize {16}; + int _sendTimeout {180}; + bool _usePassiveDcc {false}; + bool _useFastSend {false}; +}; diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 2332d8c4..39a7ceb0 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -12,6 +12,7 @@ set(SOURCES corebufferviewconfig.cpp corebufferviewmanager.cpp corecoreinfo.cpp + coredccconfig.cpp coreidentity.cpp coreignorelistmanager.cpp coreircchannel.cpp diff --git a/src/core/coredccconfig.cpp b/src/core/coredccconfig.cpp new file mode 100644 index 00000000..46dfdfb6 --- /dev/null +++ b/src/core/coredccconfig.cpp @@ -0,0 +1,46 @@ +/*************************************************************************** + * Copyright (C) 2005-2016 by the Quassel Project * + * devel@quassel-irc.org * + * * + * 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 2 of the License, or * + * (at your option) version 3. * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#include "coredccconfig.h" + +#include "core.h" +#include "coresession.h" + +constexpr auto settingsKey = "DccConfig"; + +CoreDccConfig::CoreDccConfig(CoreSession *session) + : DccConfig(session) + , _coreSession{session} +{ + // Load config from database if it exists + auto configMap = Core::getUserSetting(session->user(), settingsKey).toMap(); + if (!configMap.isEmpty()) + update(configMap); + // Otherwise, we just use the defaults initialized in the base class + + // We store our settings whenever they change + connect(this, SIGNAL(updatedRemotely()), SLOT(save())); +} + + +void CoreDccConfig::save() +{ + Core::setUserSetting(_coreSession->user(), settingsKey, toVariantMap()); +} diff --git a/src/core/coredccconfig.h b/src/core/coredccconfig.h new file mode 100644 index 00000000..1b3c49a9 --- /dev/null +++ b/src/core/coredccconfig.h @@ -0,0 +1,51 @@ +/*************************************************************************** + * Copyright (C) 2005-2016 by the Quassel Project * + * devel@quassel-irc.org * + * * + * 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 2 of the License, or * + * (at your option) version 3. * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#pragma once + +#include "dccconfig.h" + +class CoreSession; + +/** + * Core-side specialization for DccConfig. + * + * Adds the ability to load/save the settings from/to the database. + */ +class CoreDccConfig : public DccConfig +{ + Q_OBJECT +public: + /** + * Constructor. + * + * @param[in] session Pointer to the parent CoreSession (takes ownership) + */ + CoreDccConfig(CoreSession *session); + +public slots: + /** + * Saves the config to the database. + */ + void save(); + +private: + CoreSession *_coreSession {nullptr}; ///< Pointer to the parent CoreSession +}; diff --git a/src/core/coresession.cpp b/src/core/coresession.cpp index 49898b29..5c377c85 100644 --- a/src/core/coresession.cpp +++ b/src/core/coresession.cpp @@ -27,6 +27,7 @@ #include "corebuffersyncer.h" #include "corebacklogmanager.h" #include "corebufferviewmanager.h" +#include "coredccconfig.h" #include "coreeventmanager.h" #include "coreidentity.h" #include "coreignorelistmanager.h" @@ -64,6 +65,7 @@ CoreSession::CoreSession(UserId uid, bool restoreState, QObject *parent) _bufferSyncer(new CoreBufferSyncer(this)), _backlogManager(new CoreBacklogManager(this)), _bufferViewManager(new CoreBufferViewManager(_signalProxy, this)), + _dccConfig(new CoreDccConfig(this)), _ircListHelper(new CoreIrcListHelper(this)), _networkConfig(new CoreNetworkConfig("GlobalNetworkConfig", this)), _coreInfo(this), @@ -121,6 +123,7 @@ CoreSession::CoreSession(UserId uid, bool restoreState, QObject *parent) p->synchronize(_bufferSyncer); p->synchronize(&aliasManager()); p->synchronize(_backlogManager); + p->synchronize(dccConfig()); p->synchronize(ircListHelper()); p->synchronize(networkConfig()); p->synchronize(&_coreInfo); diff --git a/src/core/coresession.h b/src/core/coresession.h index fc50ab1a..950dfb25 100644 --- a/src/core/coresession.h +++ b/src/core/coresession.h @@ -35,6 +35,7 @@ class CoreBacklogManager; class CoreBufferSyncer; class CoreBufferViewManager; +class CoreDccConfig; class CoreIdentity; class CoreIrcListHelper; class CoreNetwork; @@ -87,6 +88,7 @@ public: inline CoreIgnoreListManager *ignoreListManager() { return &_ignoreListManager; } inline CoreTransferManager *transferManager() const { return _transferManager; } + inline CoreDccConfig *dccConfig() const { return _dccConfig; } // void attachNetworkConnection(NetworkConnection *conn); @@ -203,6 +205,7 @@ private: CoreBufferSyncer *_bufferSyncer; CoreBacklogManager *_backlogManager; CoreBufferViewManager *_bufferViewManager; + CoreDccConfig *_dccConfig; CoreIrcListHelper *_ircListHelper; CoreNetworkConfig *_networkConfig; CoreCoreInfo _coreInfo; -- 2.20.1