Implement core-side highlights
[quassel.git] / src / core / corenetwork.cpp
index 6f2c285..3ad9d7c 100644 (file)
@@ -214,12 +214,16 @@ void CoreNetwork::connectToIrc(bool reconnecting)
     }
     else if (_previousConnectionAttemptFailed) {
         // cycle to next server if previous connection attempt failed
+        _previousConnectionAttemptFailed = false;
         displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("Connection failed. Cycling to next Server"));
         if (++_lastUsedServerIndex >= serverList().size()) {
             _lastUsedServerIndex = 0;
         }
     }
-    _previousConnectionAttemptFailed = false;
+    else {
+        // Start out with the top server in the list
+        _lastUsedServerIndex = 0;
+    }
 
     Server server = usedServer();
     displayStatusMsg(tr("Connecting to %1:%2...").arg(server.host).arg(server.port));
@@ -542,8 +546,13 @@ void CoreNetwork::socketInitialized()
 
     socket.setSocketOption(QAbstractSocket::KeepAliveOption, true);
 
-    // Update the TokenBucket with specified rate-limiting settings
-    updateRateLimiting();
+    // Update the TokenBucket, force-enabling unlimited message rates for initial registration and
+    // capability negotiation.  networkInitialized() will call updateRateLimiting() without the
+    // force flag to apply user preferences.  When making changes, ensure that this still happens!
+    // As Quassel waits for CAP ACK/NAK and AUTHENTICATE replies, this shouldn't ever fill the IRC
+    // server receive queue and cause a kill.  "Shouldn't" being the operative word; the real world
+    // is a scary place.
+    updateRateLimiting(true);
     // Fill up the token bucket as we're connecting from scratch
     resetTokenBucket();
 
@@ -640,6 +649,10 @@ void CoreNetwork::networkInitialized()
     _disconnectExpected = false;
     _quitRequested = false;
 
+    // Update the TokenBucket with specified rate-limiting settings, removing the force-unlimited
+    // flag used for initial registration and capability negotiation.
+    updateRateLimiting();
+
     if (useAutoReconnect()) {
         // reset counter
         _autoReconnectCount = unlimitedReconnectRetries() ? -1 : autoReconnectRetries();
@@ -647,8 +660,11 @@ void CoreNetwork::networkInitialized()
 
     // restore away state
     QString awayMsg = Core::awayMessage(userId(), networkId());
-    if (!awayMsg.isEmpty())
-        userInputHandler()->handleAway(BufferInfo(), Core::awayMessage(userId(), networkId()));
+    if (!awayMsg.isEmpty()) {
+        // Don't re-apply any timestamp formatting in order to preserve escaped percent signs, e.g.
+        // '%%%%%%%%' -> '%%%%'  If processed again, it'd result in '%%'.
+        userInputHandler()->handleAway(BufferInfo(), awayMsg, true);
+    }
 
     sendPerform();
 
@@ -931,12 +947,14 @@ void CoreNetwork::setPingInterval(int interval)
 
 /******** Custom Rate Limiting ********/
 
-void CoreNetwork::updateRateLimiting()
+void CoreNetwork::updateRateLimiting(const bool forceUnlimited)
 {
-    // Always reset the delay and token bucket (safe-guard against accidentally starting the timer)
+    // Verify and apply custom rate limiting options, always resetting the delay and burst size
+    // (safe-guarding against accidentally starting the timer), but don't reset the token bucket as
+    // this may be called while connected to a server.
 
-    if (useCustomMessageRate()) {
-        // Custom message rates enabled.  Let's go for it!
+    if (useCustomMessageRate() || forceUnlimited) {
+        // Custom message rates enabled, or chosen by means of forcing unlimited.  Let's go for it!
 
         _messageDelay = messageRateDelay();
 
@@ -957,9 +975,10 @@ void CoreNetwork::updateRateLimiting()
         }
 
         // Toggle the timer according to whether or not rate limiting is enabled
-        // If we're here, useCustomMessageRate is true.  Thus, the logic becomes
-        // _skipMessageRates = (useCustomMessageRate && unlimitedMessageRate)
-        _skipMessageRates = unlimitedMessageRate();
+        // If we're here, either useCustomMessageRate or forceUnlimited is true.  Thus, the logic is
+        // _skipMessageRates = ((useCustomMessageRate && unlimitedMessageRate) || forceUnlimited)
+        // Override user preferences if called with force unlimited, only used during connect.
+        _skipMessageRates = (unlimitedMessageRate() || forceUnlimited);
         if (_skipMessageRates) {
             // If the message queue already contains messages, they need sent before disabling the
             // timer.  Set the timer to a rapid pace and let it disable itself.
@@ -984,12 +1003,12 @@ void CoreNetwork::updateRateLimiting()
     } else {
         // Custom message rates disabled.  Go for the default.
 
-        _skipMessageRates = false;   // Enable rate-limiting by default
-        // TokenBucket to avoid sending too much at once
-        _messageDelay = 2200;      // This seems to be a safe value (2.2 seconds delay)
-        _burstSize = 5;            // 5 messages at once
+        _skipMessageRates = false;  // Enable rate-limiting by default
+        _messageDelay = 2200;       // This seems to be a safe value (2.2 seconds delay)
+        _burstSize = 5;             // 5 messages at once
         if (_tokenBucket > _burstSize) {
-            // Don't let the token bucket exceed the maximum
+            // TokenBucket to avoid sending too much at once.  Don't let the token bucket exceed the
+            // maximum.
             _tokenBucket = _burstSize;
             // To fill up the token bucket, use resetRateLimiting().  Don't do that here, otherwise
             // changing the rate-limit settings while connected to a server will incorrectly reset
@@ -1041,7 +1060,7 @@ void CoreNetwork::serverCapAcknowledged(const QString &capability)
         // FIXME use event
 #ifdef HAVE_SSL
         if (!identityPtr()->sslCert().isNull()) {
-            if (IrcCap::SaslMech::maybeSupported(capValue(IrcCap::SASL), IrcCap::SaslMech::EXTERNAL)) {
+            if (saslMaybeSupports(IrcCap::SaslMech::EXTERNAL)) {
                 // EXTERNAL authentication supported, send request
                 putRawLine(serverEncode("AUTHENTICATE EXTERNAL"));
             } else {
@@ -1051,7 +1070,7 @@ void CoreNetwork::serverCapAcknowledged(const QString &capability)
             }
         } else {
 #endif
-            if (IrcCap::SaslMech::maybeSupported(capValue(IrcCap::SASL), IrcCap::SaslMech::PLAIN)) {
+            if (saslMaybeSupports(IrcCap::SaslMech::PLAIN)) {
                 // PLAIN authentication supported, send request
                 // Only working with PLAIN atm, blowfish later
                 putRawLine(serverEncode("AUTHENTICATE PLAIN"));