+ /**
+ * 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
+ };
+