Sync caps, use signal/slot, CAP NEW/DEL, polish
[quassel.git] / src / common / network.h
index b83c699..09310fd 100644 (file)
@@ -1,5 +1,5 @@
 /***************************************************************************
- *   Copyright (C) 2005-2012 by the Quassel Project                        *
+ *   Copyright (C) 2005-2016 by the Quassel Project                        *
  *   devel@quassel-irc.org                                                 *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
@@ -50,30 +50,30 @@ class Network : public SyncableObject
     Q_OBJECT
     Q_ENUMS(ConnectionState)
 
-    Q_PROPERTY(QString networkName READ networkName WRITE setNetworkName STORED false)
-    Q_PROPERTY(QString currentServer READ currentServer WRITE setCurrentServer STORED false)
-    Q_PROPERTY(QString myNick READ myNick WRITE setMyNick STORED false)
-    Q_PROPERTY(int latency READ latency WRITE setLatency STORED false)
-    Q_PROPERTY(QByteArray codecForServer READ codecForServer WRITE setCodecForServer STORED false)
-    Q_PROPERTY(QByteArray codecForEncoding READ codecForEncoding WRITE setCodecForEncoding STORED false)
-    Q_PROPERTY(QByteArray codecForDecoding READ codecForDecoding WRITE setCodecForDecoding STORED false)
-    Q_PROPERTY(IdentityId identityId READ identity WRITE setIdentity STORED false)
-    Q_PROPERTY(bool isConnected READ isConnected WRITE setConnected STORED false)
-    //Q_PROPERTY(Network::ConnectionState connectionState READ connectionState WRITE setConnectionState STORED false)
-    Q_PROPERTY(int connectionState READ connectionState WRITE setConnectionState STORED false)
-    Q_PROPERTY(bool useRandomServer READ useRandomServer WRITE setUseRandomServer STORED false)
-    Q_PROPERTY(QStringList perform READ perform WRITE setPerform STORED false)
-    Q_PROPERTY(bool useAutoIdentify READ useAutoIdentify WRITE setUseAutoIdentify STORED false)
-    Q_PROPERTY(QString autoIdentifyService READ autoIdentifyService WRITE setAutoIdentifyService STORED false)
-    Q_PROPERTY(QString autoIdentifyPassword READ autoIdentifyPassword WRITE setAutoIdentifyPassword STORED false)
-    Q_PROPERTY(bool useSasl READ useSasl WRITE setUseSasl STORED false)
-    Q_PROPERTY(QString saslAccount READ saslAccount WRITE setSaslAccount STORED false)
-    Q_PROPERTY(QString saslPassword READ saslPassword WRITE setSaslPassword STORED false)
-    Q_PROPERTY(bool useAutoReconnect READ useAutoReconnect WRITE setUseAutoReconnect STORED false)
-    Q_PROPERTY(quint32 autoReconnectInterval READ autoReconnectInterval WRITE setAutoReconnectInterval STORED false)
-    Q_PROPERTY(quint16 autoReconnectRetries READ autoReconnectRetries WRITE setAutoReconnectRetries STORED false)
-    Q_PROPERTY(bool unlimitedReconnectRetries READ unlimitedReconnectRetries WRITE setUnlimitedReconnectRetries STORED false)
-    Q_PROPERTY(bool rejoinChannels READ rejoinChannels WRITE setRejoinChannels STORED false)
+    Q_PROPERTY(QString networkName READ networkName WRITE setNetworkName)
+    Q_PROPERTY(QString currentServer READ currentServer WRITE setCurrentServer)
+    Q_PROPERTY(QString myNick READ myNick WRITE setMyNick)
+    Q_PROPERTY(int latency READ latency WRITE setLatency)
+    Q_PROPERTY(QByteArray codecForServer READ codecForServer WRITE setCodecForServer)
+    Q_PROPERTY(QByteArray codecForEncoding READ codecForEncoding WRITE setCodecForEncoding)
+    Q_PROPERTY(QByteArray codecForDecoding READ codecForDecoding WRITE setCodecForDecoding)
+    Q_PROPERTY(IdentityId identityId READ identity WRITE setIdentity)
+    Q_PROPERTY(bool isConnected READ isConnected WRITE setConnected)
+    //Q_PROPERTY(Network::ConnectionState connectionState READ connectionState WRITE setConnectionState)
+    Q_PROPERTY(int connectionState READ connectionState WRITE setConnectionState)
+    Q_PROPERTY(bool useRandomServer READ useRandomServer WRITE setUseRandomServer)
+    Q_PROPERTY(QStringList perform READ perform WRITE setPerform)
+    Q_PROPERTY(bool useAutoIdentify READ useAutoIdentify WRITE setUseAutoIdentify)
+    Q_PROPERTY(QString autoIdentifyService READ autoIdentifyService WRITE setAutoIdentifyService)
+    Q_PROPERTY(QString autoIdentifyPassword READ autoIdentifyPassword WRITE setAutoIdentifyPassword)
+    Q_PROPERTY(bool useSasl READ useSasl WRITE setUseSasl)
+    Q_PROPERTY(QString saslAccount READ saslAccount WRITE setSaslAccount)
+    Q_PROPERTY(QString saslPassword READ saslPassword WRITE setSaslPassword)
+    Q_PROPERTY(bool useAutoReconnect READ useAutoReconnect WRITE setUseAutoReconnect)
+    Q_PROPERTY(quint32 autoReconnectInterval READ autoReconnectInterval WRITE setAutoReconnectInterval)
+    Q_PROPERTY(quint16 autoReconnectRetries READ autoReconnectRetries WRITE setAutoReconnectRetries)
+    Q_PROPERTY(bool unlimitedReconnectRetries READ unlimitedReconnectRetries WRITE setUnlimitedReconnectRetries)
+    Q_PROPERTY(bool rejoinChannels READ rejoinChannels WRITE setRejoinChannels)
 
 public :
         enum ConnectionState {
@@ -132,6 +132,18 @@ public :
 
     bool isChannelName(const QString &channelname) const;
 
+    /**
+     * Checks if the target counts as a STATUSMSG
+     *
+     * Status messages are prefixed with one or more characters from the server-provided STATUSMSG
+     * if available, otherwise "@" and "+" are assumed.  Generally, status messages sent to a
+     * channel are only visible to those with the same or higher permissions, e.g. voiced.
+     *
+     * @param[in] target Name of destination, e.g. a channel or query
+     * @returns True if a STATUSMSG, otherwise false
+     */
+    bool isStatusMsg(const QString &target) const;
+
     inline bool isConnected() const { return _connected; }
     //Network::ConnectionState connectionState() const;
     inline int connectionState() const { return _connectionState; }
@@ -152,6 +164,18 @@ public :
     inline IdentityId identity() const { return _identity; }
     QStringList nicks() const;
     inline QStringList channels() const { return _ircChannels.keys(); }
+    /**
+     * Gets the list of available capabilities.
+     *
+     * @returns QStringList of available capabilities
+     */
+    inline const QStringList caps() const { return QStringList(_caps.keys()); }
+    /**
+     * Gets the list of enabled (acknowledged) capabilities.
+     *
+     * @returns QStringList of enabled (acknowledged) capabilities
+     */
+    inline const QStringList capsEnabled() const { return _capsEnabled; }
     inline const ServerList &serverList() const { return _serverList; }
     inline bool useRandomServer() const { return _useRandomServer; }
     inline const QStringList &perform() const { return _perform; }
@@ -177,6 +201,26 @@ public :
     bool supports(const QString &param) const { return _supports.contains(param); }
     QString support(const QString &param) const;
 
+    /**
+     * Checks if a given capability is acknowledged and active.
+     *
+     * @param[in] capability Name of capability
+     * @returns True if acknowledged (active), otherwise false
+     */
+    inline bool capEnabled(const QString &capability) const { return _capsEnabled.contains(capability.toLower()); }
+    // IRCv3 specs all use lowercase capability names
+
+    /**
+     * Gets the value of an available capability, e.g. for SASL, "EXTERNAL,PLAIN".
+     *
+     * @param[in] capability Name of capability
+     * @returns Value of capability if one was specified, otherwise empty string
+     */
+    QString capValue(const QString &capability) const { return _caps.value(capability.toLower()); }
+    // IRCv3 specs all use lowercase capability names
+    // QHash returns the default constructed value if not found, in this case, empty string
+    // See:  https://doc.qt.io/qt-4.8/qhash.html#value
+
     IrcUser *newIrcUser(const QString &hostmask, const QVariantMap &initData = QVariantMap());
     inline IrcUser *newIrcUser(const QByteArray &hostmask) { return newIrcUser(decodeServerString(hostmask)); }
     IrcUser *ircUser(QString nickname) const;
@@ -213,10 +257,6 @@ public :
     inline bool autoAwayActive() const { return _autoAwayActive; }
     inline void setAutoAwayActive(bool active) { _autoAwayActive = active; }
 
-    static QStringList presetNetworks(bool onlyDefault = false);
-    static QStringList presetDefaultChannels(const QString &networkName);
-    static NetworkInfo networkInfoFromPreset(const QString &networkName);
-
 public slots:
     void setNetworkName(const QString &networkName);
     void setCurrentServer(const QString &currentServer);
@@ -248,19 +288,90 @@ public slots:
     void addSupport(const QString &param, const QString &value = QString());
     void removeSupport(const QString &param);
 
+    // IRCv3 capability negotiation (can be connected to signals)
+
+    /**
+     * Add an available capability, optionally providing a value.
+     *
+     * This may happen during first connect, or at any time later if a new capability becomes
+     * available (e.g. SASL service starting).
+     *
+     * @param[in] capability Name of the capability
+     * @param[in] value
+     * @parblock
+     * Optional value of the capability, e.g. sasl=plain.
+     * @endparblock
+     */
+    void addCap(const QString &capability, const QString &value = QString());
+
+    /**
+     * Marks a capability as acknowledged (enabled by the IRC server).
+     *
+     * @param[in] capability Name of the capability
+     */
+    void acknowledgeCap(const QString &capability);
+
+    /**
+     * Removes a capability from the list of available capabilities.
+     *
+     * This may happen during first connect, or at any time later if an existing capability becomes
+     * unavailable (e.g. SASL service stopping).  This also removes the capability from the list
+     * of acknowledged capabilities.
+     *
+     * @param[in] capability Name of the capability
+     */
+    void removeCap(const QString &capability);
+
+    /**
+     * Clears all capabilities from the list of available capabilities.
+     *
+     * This also removes the capability from the list of acknowledged capabilities.
+     */
+    void clearCaps();
+
     inline void addIrcUser(const QString &hostmask) { newIrcUser(hostmask); }
     inline void addIrcChannel(const QString &channel) { newIrcChannel(channel); }
 
     //init geters
     QVariantMap initSupports() const;
+    /**
+     * Get the initial list of available capabilities.
+     *
+     * @return QVariantMap of <QString, QString> indicating available capabilities and values
+     */
+    QVariantMap initCaps() const;
+    /**
+     * Get the initial list of enabled (acknowledged) capabilities.
+     *
+     * @return QVariantList of QString indicating enabled (acknowledged) capabilities and values
+     */
+    QVariantList initCapsEnabled() const { return toVariantList(capsEnabled()); }
     inline QVariantList initServerList() const { return toVariantList(serverList()); }
     virtual QVariantMap initIrcUsersAndChannels() const;
 
     //init seters
     void initSetSupports(const QVariantMap &supports);
+    /**
+     * Initialize the list of available capabilities.
+     *
+     * @param[in] caps QVariantMap of <QString, QString> indicating available capabilities and values
+     */
+    void initSetCaps(const QVariantMap &caps);
+    /**
+     * Initialize the list of enabled (acknowledged) capabilities.
+     *
+     * @param[in] caps QVariantList of QString indicating enabled (acknowledged) capabilities and values
+     */
+    inline void initSetCapsEnabled(const QVariantList &capsEnabled) { _capsEnabled = fromVariantList<QString>(capsEnabled); }
     inline void initSetServerList(const QVariantList &serverList) { _serverList = fromVariantList<Server>(serverList); }
     virtual void initSetIrcUsersAndChannels(const QVariantMap &usersAndChannels);
 
+    /**
+     * Update IrcUser hostmask and username from mask, creating an IrcUser if one does not exist.
+     *
+     * @param[in] mask   Full nick!user@hostmask string
+     * @return IrcUser of the matching nick if exists, otherwise a new IrcUser
+     */
     IrcUser *updateNickFromMask(const QString &mask);
 
     // these slots are to keep the hashlists of all users and the
@@ -311,6 +422,34 @@ signals:
 //   void supportAdded(const QString &param, const QString &value);
 //   void supportRemoved(const QString &param);
 
+    // IRCv3 capability negotiation (can drive other slots)
+    /**
+     * Indicates a capability is now available, with optional value in Network::capValue().
+     *
+     * @see Network::addCap()
+     *
+     * @param[in] capability Name of the capability
+     */
+    void capAdded (const QString &capability);
+
+    /**
+     * Indicates a capability was acknowledged (enabled by the IRC server).
+     *
+     * @see Network::acknowledgeCap()
+     *
+     * @param[in] capability Name of the capability
+     */
+    void capAcknowledged(const QString &capability);
+
+    /**
+     * Indicates a capability was removed from the list of available capabilities.
+     *
+     * @see Network::removeCap()
+     *
+     * @param[in] capability Name of the capability
+     */
+    void capRemoved(const QString &capability);
+
 //   void ircUserAdded(const QString &hostmask);
     void ircUserAdded(IrcUser *);
 //   void ircChannelAdded(const QString &channelname);
@@ -344,6 +483,13 @@ private:
     QHash<QString, IrcChannel *> _ircChannels; // stores all known channels
     QHash<QString, QString> _supports; // stores results from RPL_ISUPPORT
 
+    QHash<QString, QString> _caps;  /// Capabilities supported by the IRC server
+    // By synchronizing the supported capabilities, the client could suggest certain behaviors, e.g.
+    // in the Network settings dialog, recommending SASL instead of using NickServ, or warning if
+    // SASL EXTERNAL isn't available.
+    QStringList _capsEnabled;       /// Enabled capabilities that received 'CAP ACK'
+    // _capsEnabled uses the same values from the <name>=<value> pairs stored in _caps
+
     ServerList _serverList;
     bool _useRandomServer;
     QStringList _perform;
@@ -372,8 +518,6 @@ private:
 
     bool _autoAwayActive; // when this is active handle305 and handle306 don't trigger any output
 
-    static QString _networksIniPath;
-
     friend class IrcUser;
     friend class IrcChannel;
 };