Finish 64-bit time conversion, modify protocol
[quassel.git] / src / core / corenetwork.cpp
index 30896aa..51c6188 100644 (file)
@@ -1,5 +1,5 @@
 /***************************************************************************
- *   Copyright (C) 2005-2016 by the Quassel Project                        *
+ *   Copyright (C) 2005-2018 by the Quassel Project                        *
  *   devel@quassel-irc.org                                                 *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
@@ -63,6 +63,11 @@ CoreNetwork::CoreNetwork(const NetworkId &networkid, CoreSession *session)
         _channelKeys[chan.toLower()] = channels[chan];
     }
 
+    QHash<QString, QByteArray> bufferCiphers = coreSession()->bufferCiphers(networkId());
+    foreach(QString buffer, bufferCiphers.keys()) {
+        storeChannelCipherKey(buffer.toLower(), bufferCiphers[buffer]);
+    }
+
     connect(networkConfig(), SIGNAL(pingTimeoutEnabledSet(bool)), SLOT(enablePingTimeout(bool)));
     connect(networkConfig(), SIGNAL(pingIntervalSet(int)), SLOT(setPingInterval(int)));
     connect(networkConfig(), SIGNAL(autoWhoEnabledSet(bool)), SLOT(setAutoWhoEnabled(bool)));
@@ -214,12 +219,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));
@@ -237,8 +246,11 @@ void CoreNetwork::connectToIrc(bool reconnecting)
 
     // Qt caches DNS entries for a minute, resulting in round-robin (e.g. for chat.freenode.net) not working if several users
     // connect at a similar time. QHostInfo::fromName(), however, always performs a fresh lookup, overwriting the cache entry.
-    QHostInfo::fromName(server.host);
-
+    if (! server.useProxy) {
+        //Avoid hostname lookups when a proxy is specified. The lookups won't use the proxy and may therefore leak the DNS
+        //hostname of the server. Qt's DNS cache also isn't used by the proxy so we don't need to refresh the entry.
+        QHostInfo::fromName(server.host);
+    }
 #ifdef HAVE_SSL
     if (server.useSsl) {
         CoreIdentity *identity = identityPtr();
@@ -435,6 +447,7 @@ void CoreNetwork::setCipherKey(const QString &target, const QByteArray &key)
     CoreIrcChannel *c = qobject_cast<CoreIrcChannel*>(ircChannel(target));
     if (c) {
         c->setEncrypted(c->cipher()->setKey(key));
+        coreSession()->setBufferCipher(networkId(), target, key);
         return;
     }
 
@@ -444,6 +457,7 @@ void CoreNetwork::setCipherKey(const QString &target, const QByteArray &key)
 
     if (u) {
         u->setEncrypted(u->cipher()->setKey(key));
+        coreSession()->setBufferCipher(networkId(), target, key);
         return;
     }
 }
@@ -656,8 +670,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();
 
@@ -891,12 +908,17 @@ void CoreNetwork::doAutoReconnect()
 
 void CoreNetwork::sendPing()
 {
-    uint now = QDateTime::currentDateTime().toTime_t();
+    qint64 now = QDateTime::currentDateTime().toMSecsSinceEpoch();
     if (_pingCount != 0) {
         qDebug() << "UserId:" << userId() << "Network:" << networkName() << "missed" << _pingCount << "pings."
                  << "BA:" << socket.bytesAvailable() << "BTW:" << socket.bytesToWrite();
     }
-    if ((int)_pingCount >= networkConfig()->maxPingCount() && now - _lastPingTime <= (uint)(_pingTimer.interval() / 1000) + 1) {
+    if ((int)_pingCount >= networkConfig()->maxPingCount()
+            && (now - _lastPingTime) <= (_pingTimer.interval() + (1 * 1000))) {
+        // In transitioning to 64-bit time, the interval no longer needs converted down to seconds.
+        // However, to reduce the risk of breaking things by changing past behavior, we still allow
+        // up to 1 second missed instead of enforcing a stricter 1 millisecond allowance.
+        //
         // the second check compares the actual elapsed time since the last ping and the pingTimer interval
         // if the interval is shorter then the actual elapsed time it means that this thread was somehow blocked
         // and unable to even handle a ping answer. So we ignore those misses.
@@ -1053,7 +1075,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 {
@@ -1063,7 +1085,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"));
@@ -1200,9 +1222,10 @@ void CoreNetwork::beginCapNegotiation()
                tr("Ready to negotiate (found: %1)").arg(caps().join(", ")));
 
     // Build a list of queued capabilities, starting with individual, then bundled, only adding the
-    // comma separator between the two if needed.
+    // comma separator between the two if needed (both individual and bundled caps exist).
     QString queuedCapsDisplay =
-            (!_capsQueuedIndividual.empty() ? _capsQueuedIndividual.join(", ") + ", " : "")
+            _capsQueuedIndividual.join(", ")
+            + ((!_capsQueuedIndividual.empty() && !_capsQueuedBundled.empty()) ? ", " : "")
             + _capsQueuedBundled.join(", ");
     displayMsg(Message::Server, BufferInfo::StatusBuffer, "",
                tr("Negotiating capabilities (requesting: %1)...").arg(queuedCapsDisplay));