X-Git-Url: https://git.quassel-irc.org/?a=blobdiff_plain;f=src%2Fcore%2Fcorenetwork.h;h=906f60ae0e3c674c80256b460d50cc23195d6de9;hb=809f86daa290cf67f9b30445b26378fff0030672;hp=d596c5380c17c37be925659c48ade627f7965e11;hpb=3966090a1e7093c417560f7ee13ab310215d9ccd;p=quassel.git diff --git a/src/core/corenetwork.h b/src/core/corenetwork.h index d596c538..906f60ae 100644 --- a/src/core/corenetwork.h +++ b/src/core/corenetwork.h @@ -110,7 +110,8 @@ public: * * @returns True if in progress, otherwise false */ - inline bool capNegotiationInProgress() const { return !_capsQueued.empty(); } + inline bool capNegotiationInProgress() const { return (!_capsQueuedIndividual.empty() || + !_capsQueuedBundled.empty()); } /** * Queues a capability to be requested. @@ -130,12 +131,37 @@ public: */ 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 { @@ -169,6 +195,17 @@ public slots: void disconnectFromIrc(bool requested = true, const QString &reason = QString(), bool withReconnect = false, bool forceImmediate = false); + /** + * Forcibly close the IRC server socket, waiting for it to close. + * + * Call CoreNetwork::disconnectFromIrc() first, allow the event loop to run, then if you need to + * be sure the network's disconencted (e.g. clean-up), call this. + * + * @param msecs Maximum time to wait for socket to close, in milliseconds. + * @return True if socket closes successfully; false if error occurs or timeout reached + */ + bool forceDisconnect(int msecs = 1000); + void userInput(BufferInfo bufferInfo, QString msg); /** @@ -372,6 +409,10 @@ private: bool _quitRequested; QString _quitReason; + bool _disconnectExpected; /// If true, connection is quitting, expect a socket close + // This avoids logging a spurious RemoteHostClosedError whenever disconnect is called without + // specifying a permanent (saved to core session) disconnect. + bool _previousConnectionAttemptFailed; int _lastUsedServerIndex; @@ -386,18 +427,40 @@ private: // Maintain a list of CAPs that are being checked; if empty, negotiation finished // See http://ircv3.net/specs/core/capability-negotiation-3.2.html - QStringList _capsQueued; /// Capabilities to be checked - bool _capNegotiationActive; /// Whether or not full capability negotiation was started + QStringList _capsQueuedIndividual; /// Capabilities to check that require one at a time requests + QStringList _capsQueuedBundled; /// Capabilities to check that can be grouped together + QStringList _capsQueuedLastBundle; /// Most recent capability bundle requested (no individuals) + // Some capabilities, such as SASL, require follow-up messages to be fully enabled. These + // capabilities should not be grouped with others to avoid requesting new capabilities while the + // previous capability is still being set up. + // Additionally, IRC servers can choose to send a 'NAK' to any set of requested capabilities. + // If this happens, we need a way to retry each capability individually in order to avoid having + // one failing capability (e.g. SASL) block all other capabilities. + + bool _capNegotiationActive; /// Whether or not full capability negotiation was started // Avoid displaying repeat "negotiation finished" messages - bool _capInitialNegotiationEnded; /// Whether or not initial capability negotiation finished + bool _capInitialNegotiationEnded; /// Whether or not initial capability negotiation finished // Avoid sending repeat "CAP END" replies when registration is already ended /** - * Gets the next capability to request, removing it from the queue. + * Gets the next set of capabilities to request, removing them from the queue. + * + * May return one or multiple space-separated capabilities, depending on queue. + * + * @returns Space-separated names of capabilities to request, or empty string if none remain + */ + QString takeQueuedCaps(); + + /** + * Maximum length of a single 'CAP REQ' command. + * + * To be safe, 100 chars. Higher numbers should be possible; this is following the conservative + * minimum number of characters that IRC servers must return in CAP NAK replies. This also + * means CAP NAK replies will contain the full list of denied capabilities. * - * @returns Name of capability to request + * See: http://ircv3.net/specs/core/capability-negotiation-3.1.html */ - QString takeQueuedCap(); + const int maxCapRequestLength = 100; QTimer _tokenBucketTimer; int _messageDelay; // token refill speed in ms