dcc: Add persistent settings for core-side DCC
authorManuel Nickschas <sputnick@quassel-irc.org>
Fri, 7 Oct 2016 22:40:46 +0000 (00:40 +0200)
committerManuel Nickschas <sputnick@quassel-irc.org>
Fri, 7 Oct 2016 22:40:46 +0000 (00:40 +0200)
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
src/client/client.h
src/common/CMakeLists.txt
src/common/dccconfig.cpp [new file with mode: 0644]
src/common/dccconfig.h [new file with mode: 0644]
src/core/CMakeLists.txt
src/core/coredccconfig.cpp [new file with mode: 0644]
src/core/coredccconfig.h [new file with mode: 0644]
src/core/coresession.cpp
src/core/coresession.h

index 9116541..5319a9a 100644 (file)
@@ -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();
 
index 9815352..ec5e955 100644 (file)
@@ -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;
index 56c562c..a022756 100644 (file)
@@ -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 (file)
index 0000000..ce826b3
--- /dev/null
@@ -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 <QMetaProperty>
+
+#include "types.h"
+
+INIT_SYNCABLE_OBJECT(DccConfig)
+
+DccConfig::DccConfig(QObject *parent)
+    : SyncableObject(parent)
+{
+    static auto regTypes = []() -> bool {
+        qRegisterMetaTypeStreamOperators<IpDetectionMode>("DccConfig::IpDetectionMode");
+        qRegisterMetaTypeStreamOperators<PortSelectionMode>("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<QHostAddress>() != other.property(propName).value<QHostAddress>())
+                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 (file)
index 0000000..b4a34f8
--- /dev/null
@@ -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 <QHostAddress>
+
+#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};
+};
index 2332d8c..39a7ceb 100644 (file)
@@ -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 (file)
index 0000000..46dfdfb
--- /dev/null
@@ -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 (file)
index 0000000..1b3c49a
--- /dev/null
@@ -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
+};
index 49898b2..5c377c8 100644 (file)
@@ -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);
index fc50ab1..950dfb2 100644 (file)
@@ -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;