Really use Remote Highlights for nick, not Local
[quassel.git] / src / common / network.cpp
index 4e14af4..8e2eed4 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  *
@@ -21,6 +21,7 @@
 #include <QTextCodec>
 
 #include "network.h"
+#include "peer.h"
 
 QTextCodec *Network::_defaultCodecForServer = 0;
 QTextCodec *Network::_defaultCodecForEncoding = 0;
@@ -241,6 +242,28 @@ QString Network::support(const QString &param) const
 }
 
 
+bool Network::saslMaybeSupports(const QString &saslMechanism) const
+{
+    if (!capAvailable(IrcCap::SASL)) {
+        // If SASL's not advertised at all, it's likely the mechanism isn't supported, as per specs.
+        // Unfortunately, we don't know for sure, but Quassel won't request SASL without it being
+        // advertised, anyways.
+        // This may also occur if the network's disconnected or negotiation hasn't yet happened.
+        return false;
+    }
+
+    // Get the SASL capability value
+    QString saslCapValue = capValue(IrcCap::SASL);
+    // SASL mechanisms are only specified in capability values as part of SASL 3.2.  In SASL 3.1,
+    // it's handled differently.  If we don't know via capability value, assume it's supported to
+    // reduce the risk of breaking existing setups.
+    // See: http://ircv3.net/specs/extensions/sasl-3.1.html
+    // And: http://ircv3.net/specs/extensions/sasl-3.2.html
+    return (saslCapValue.length() == 0)
+            || (saslCapValue.contains(saslMechanism, Qt::CaseInsensitive));
+}
+
+
 IrcUser *Network::newIrcUser(const QString &hostmask, const QVariantMap &initData)
 {
     QString nick(nickFromMask(hostmask).toLower());
@@ -707,9 +730,10 @@ void Network::setUseCustomMessageRate(bool useCustomRate)
 void Network::setMessageRateBurstSize(quint32 burstSize)
 {
     if (burstSize < 1) {
-        // Can't go slower than one message at a time
-        qWarning() << "Received invalid setMessageRateBurstSize data, cannot have zero message "
-                      "burst size!" << burstSize;
+        // Can't go slower than one message at a time.  Also blocks old clients from trying to set
+        // this to 0.
+        qDebug() << "Received invalid setMessageRateBurstSize data - message burst size must be "
+                    "non-zero positive, given" << burstSize;
         return;
     }
     if (_messageRateBurstSize != burstSize) {
@@ -723,6 +747,13 @@ void Network::setMessageRateBurstSize(quint32 burstSize)
 
 void Network::setMessageRateDelay(quint32 messageDelay)
 {
+    if (messageDelay == 0) {
+        // Nonsensical to have no delay - just check the Unlimited box instead.  Also blocks old
+        // clients from trying to set this to 0.
+        qDebug() << "Received invalid setMessageRateDelay data - message delay must be non-zero "
+                    "positive, given" << messageDelay;
+        return;
+    }
     if (_messageRateDelay != messageDelay) {
         _messageRateDelay = messageDelay;
         SYNC(ARG(messageDelay))
@@ -851,6 +882,8 @@ QVariantMap Network::initCaps() const
 // (without compression) with a decent amount of IrcUsers.
 QVariantMap Network::initIrcUsersAndChannels() const
 {
+    Q_ASSERT(proxy());
+    Q_ASSERT(proxy()->targetPeer());
     QVariantMap usersAndChannels;
 
     if (_ircUsers.count()) {
@@ -858,7 +891,21 @@ QVariantMap Network::initIrcUsersAndChannels() const
         QHash<QString, IrcUser *>::const_iterator it = _ircUsers.begin();
         QHash<QString, IrcUser *>::const_iterator end = _ircUsers.end();
         while (it != end) {
-            const QVariantMap &map = it.value()->toVariantMap();
+            QVariantMap map = it.value()->toVariantMap();
+            // If the peer doesn't support LongTime, replace the lastAwayMessageTime field
+            // with the 32-bit numerical seconds value (lastAwayMessage) used in older versions
+            if (!proxy()->targetPeer()->hasFeature(Quassel::Feature::LongTime)) {
+#if QT_VERSION >= 0x050800
+                int lastAwayMessage = it.value()->lastAwayMessageTime().toSecsSinceEpoch();
+#else
+                // toSecsSinceEpoch() was added in Qt 5.8.  Manually downconvert to seconds for now.
+                // See https://doc.qt.io/qt-5/qdatetime.html#toMSecsSinceEpoch
+                int lastAwayMessage = it.value()->lastAwayMessageTime().toMSecsSinceEpoch() / 1000;
+#endif
+                map.remove("lastAwayMessageTime");
+                map["lastAwayMessage"] = lastAwayMessage;
+            }
+
             QVariantMap::const_iterator mapiter = map.begin();
             while (mapiter != map.end()) {
                 users[mapiter.key()] << mapiter.value();
@@ -900,6 +947,7 @@ QVariantMap Network::initIrcUsersAndChannels() const
 void Network::initSetIrcUsersAndChannels(const QVariantMap &usersAndChannels)
 {
     Q_ASSERT(proxy());
+    Q_ASSERT(proxy()->sourcePeer());
     if (isInitialized()) {
         qWarning() << "Network" << networkId() << "received init data for users and channels although there already are known users or channels!";
         return;
@@ -924,6 +972,22 @@ void Network::initSetIrcUsersAndChannels(const QVariantMap &usersAndChannels)
         QVariantMap map;
         foreach(const QString &key, users.keys())
             map[key] = users[key].toList().at(i);
+
+        // If the peer doesn't support LongTime, upconvert the lastAwayMessageTime field
+        // from the 32-bit numerical seconds value used in older versions to QDateTime
+        if (!proxy()->sourcePeer()->hasFeature(Quassel::Feature::LongTime)) {
+            QDateTime lastAwayMessageTime = QDateTime();
+            lastAwayMessageTime.setTimeSpec(Qt::UTC);
+#if QT_VERSION >= 0x050800
+            lastAwayMessageTime.fromSecsSinceEpoch(map.take("lastAwayMessage").toInt());
+#else
+            // toSecsSinceEpoch() was added in Qt 5.8.  Manually downconvert to seconds for now.
+            // See https://doc.qt.io/qt-5/qdatetime.html#toMSecsSinceEpoch
+            lastAwayMessageTime.fromMSecsSinceEpoch(map.take("lastAwayMessage").toInt() * 1000);
+#endif
+            map["lastAwayMessageTime"] = lastAwayMessageTime;
+        }
+
         newIrcUser(map["nick"].toString(), map); // newIrcUser() properly handles the hostmask being just the nick
     }