- CoreNetwork(const NetworkId &networkid, CoreSession *session);
- ~CoreNetwork();
- inline virtual const QMetaObject *syncMetaObject() const { return &Network::staticMetaObject; }
-
- inline CoreIdentity *identityPtr() const { return coreSession()->identity(identity()); }
- inline CoreSession *coreSession() const { return _coreSession; }
- inline CoreNetworkConfig *networkConfig() const { return coreSession()->networkConfig(); }
-
- inline CoreUserInputHandler *userInputHandler() const { return _userInputHandler; }
- inline CoreIgnoreListManager *ignoreListManager() { return coreSession()->ignoreListManager(); }
-
- //! Decode a string using the server (network) decoding.
- inline QString serverDecode(const QByteArray &string) const { return decodeServerString(string); }
-
- //! Decode a string using a channel-specific encoding if one is set (and use the standard encoding else).
- QString channelDecode(const QString &channelName, const QByteArray &string) const;
-
- //! Decode a string using an IrcUser-specific encoding, if one exists (using the standaed encoding else).
- QString userDecode(const QString &userNick, const QByteArray &string) const;
-
- //! Encode a string using the server (network) encoding.
- inline QByteArray serverEncode(const QString &string) const { return encodeServerString(string); }
-
- //! Encode a string using the channel-specific encoding, if set, and use the standard encoding else.
- QByteArray channelEncode(const QString &channelName, const QString &string) const;
-
- //! Encode a string using the user-specific encoding, if set, and use the standard encoding else.
- QByteArray userEncode(const QString &userNick, const QString &string) const;
-
- inline QString channelKey(const QString &channel) const { return _channelKeys.value(channel.toLower(), QString()); }
-
- inline bool isAutoWhoInProgress(const QString &channel) const { return _autoWhoPending.value(channel.toLower(), 0); }
-
- inline UserId userId() const { return _coreSession->user(); }
+ CoreNetwork(const NetworkId &networkid, CoreSession *session);
+ ~CoreNetwork();
+ inline virtual const QMetaObject *syncMetaObject() const { return &Network::staticMetaObject; }
+
+ inline CoreIdentity *identityPtr() const { return coreSession()->identity(identity()); }
+ inline CoreSession *coreSession() const { return _coreSession; }
+ inline CoreNetworkConfig *networkConfig() const { return coreSession()->networkConfig(); }
+
+ inline CoreUserInputHandler *userInputHandler() const { return _userInputHandler; }
+ inline CoreIgnoreListManager *ignoreListManager() { return coreSession()->ignoreListManager(); }
+
+ //! Decode a string using the server (network) decoding.
+ inline QString serverDecode(const QByteArray &string) const { return decodeServerString(string); }
+
+ //! Decode a string using a channel-specific encoding if one is set (and use the standard encoding else).
+ QString channelDecode(const QString &channelName, const QByteArray &string) const;
+
+ //! Decode a string using an IrcUser-specific encoding, if one exists (using the standaed encoding else).
+ QString userDecode(const QString &userNick, const QByteArray &string) const;
+
+ //! Encode a string using the server (network) encoding.
+ inline QByteArray serverEncode(const QString &string) const { return encodeServerString(string); }
+
+ //! Encode a string using the channel-specific encoding, if set, and use the standard encoding else.
+ QByteArray channelEncode(const QString &channelName, const QString &string) const;
+
+ //! Encode a string using the user-specific encoding, if set, and use the standard encoding else.
+ QByteArray userEncode(const QString &userNick, const QString &string) const;
+
+ inline QString channelKey(const QString &channel) const { return _channelKeys.value(channel.toLower(), QString()); }
+
+ inline QByteArray readChannelCipherKey(const QString &channel) const { return _cipherKeys.value(channel.toLower()); }
+ inline void storeChannelCipherKey(const QString &channel, const QByteArray &key) { _cipherKeys[channel.toLower()] = key; }
+
+ inline bool isAutoWhoInProgress(const QString &channel) const { return _autoWhoPending.value(channel.toLower(), 0); }
+
+ inline UserId userId() const { return _coreSession->user(); }
+
+ inline QAbstractSocket::SocketState socketState() const { return socket.state(); }
+ inline bool socketConnected() const { return socket.state() == QAbstractSocket::ConnectedState; }
+ inline QHostAddress localAddress() const { return socket.localAddress(); }
+ inline QHostAddress peerAddress() const { return socket.peerAddress(); }
+ inline quint16 localPort() const { return socket.localPort(); }
+ inline quint16 peerPort() const { return socket.peerPort(); }
+
+ /**
+ * Gets whether or not a disconnect was expected.
+ *
+ * Distinguishes desired quits from unexpected disconnections such as socket errors or timeouts.
+ *
+ * @return True if disconnect was requested, otherwise false.
+ */
+ inline bool disconnectExpected() const { return _disconnectExpected; }
+
+ QList<QList<QByteArray>> splitMessage(const QString &cmd, const QString &message, std::function<QList<QByteArray>(QString &)> cmdGenerator);
+
+ // IRCv3 capability negotiation
+
+ /**
+ * Checks if capability negotiation is currently ongoing.
+ *
+ * @returns True if in progress, otherwise false
+ */
+ inline bool capNegotiationInProgress() const { return (!_capsQueuedIndividual.empty() ||
+ !_capsQueuedBundled.empty()); }
+
+ /**
+ * Queues a capability to be requested.
+ *
+ * Adds to the list of capabilities being requested. If non-empty, CAP REQ messages are sent
+ * to the IRC server. This may happen at login or if capabilities are announced via CAP NEW.
+ *
+ * @param[in] capability Name of the capability
+ */
+ void queueCap(const QString &capability);
+
+ /**
+ * Begins capability negotiation if capabilities are queued, otherwise returns.
+ *
+ * If any capabilities are queued, this will begin the cycle of taking each capability and
+ * requesting it. When no capabilities remain, capability negotiation is suitably ended.
+ */
+ void beginCapNegotiation();
+
+ /**
+ * Ends capability negotiation.
+ *
+ * This won't have effect if other CAP commands are in the command queue before calling this
+ * command. It should only be called when capability negotiation is complete.
+ */
+ void endCapNegotiation();
+
+ /**
+ * Queues the most recent capability set for retrying individually.
+ *
+ * Retries the most recent bundle of capabilities one at a time instead of as a group, working
+ * around the issue that IRC servers can deny a group of requested capabilities without
+ * indicating which capabilities failed.
+ *
+ * See: http://ircv3.net/specs/core/capability-negotiation-3.1.html
+ *
+ * This does NOT call CoreNetwork::sendNextCap(). Call that when ready afterwards. Does
+ * nothing if the last capability tried was individual instead of a set.
+ */
+ void retryCapsIndividually();
+
+ /**
+ * List of capabilities requiring further core<->server messages to configure.
+ *
+ * For example, SASL requires the back-and-forth of AUTHENTICATE, so the next capability cannot
+ * be immediately sent.
+ *
+ * Any capabilities in this list must call CoreNetwork::sendNextCap() on their own and they will
+ * not be batched together with other capabilities.
+ *
+ * See: http://ircv3.net/specs/extensions/sasl-3.2.html
+ */
+ const QStringList capsRequiringConfiguration = QStringList {
+ IrcCap::SASL
+ };