[Followup PR-495] Fixes backwards compatibility issues
[quassel.git] / src / common / ircuser.cpp
index 9e792ba..ec1ecb1 100644 (file)
@@ -1,5 +1,5 @@
 /***************************************************************************
- *   Copyright (C) 2005-09 by the Quassel Project                          *
+ *   Copyright (C) 2005-2020 by the Quassel Project                        *
  *   devel@quassel-irc.org                                                 *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
  *   You should have received a copy of the GNU General Public License     *
  *   along with this program; if not, write to the                         *
  *   Free Software Foundation, Inc.,                                       *
- *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
  ***************************************************************************/
 
 #include "ircuser.h"
-#include "util.h"
 
+#include <QDebug>
+#include <QTextCodec>
+
+#include "ircchannel.h"
 #include "network.h"
 #include "signalproxy.h"
-#include "ircchannel.h"
-
-#include <QTextCodec>
-#include <QDebug>
+#include "util.h"
 
-INIT_SYNCABLE_OBJECT(IrcUser)
-IrcUser::IrcUser(const QString &hostmask, Network *network) : SyncableObject(network),
-    _initialized(false),
-    _nick(nickFromMask(hostmask)),
-    _user(userFromMask(hostmask)),
-    _host(hostFromMask(hostmask)),
-    _realName(),
-    _awayMessage(),
-    _away(false),
-    _server(),
+IrcUser::IrcUser(const QString& hostmask, Network* network)
+    : SyncableObject(network)
+    , _initialized(false)
+    , _nick(nickFromMask(hostmask))
+    , _user(userFromMask(hostmask))
+    , _host(hostFromMask(hostmask))
+    , _realName()
+    , _awayMessage()
+    , _away(false)
+    , _server()
+    ,
     // _idleTime(QDateTime::currentDateTime()),
-    _ircOperator(),
-    _lastAwayMessage(0),
-    _whoisServiceReply(),
-    _network(network),
-    _codecForEncoding(0),
-    _codecForDecoding(0)
+    _ircOperator()
+    , _lastAwayMessageTime()
+    , _whoisServiceReply()
+    , _encrypted(false)
+    , _network(network)
+    , _codecForEncoding(nullptr)
+    , _codecForDecoding(nullptr)
 {
     updateObjectName();
+    _lastAwayMessageTime.setTimeSpec(Qt::UTC);
+    _lastAwayMessageTime.setMSecsSinceEpoch(0);
 }
 
-
-IrcUser::~IrcUser()
-{
-}
-
-
 // ====================
 //  PUBLIC:
 // ====================
@@ -64,58 +62,54 @@ QString IrcUser::hostmask() const
     return QString("%1!%2@%3").arg(nick()).arg(user()).arg(host());
 }
 
-
 QDateTime IrcUser::idleTime()
 {
-    if (QDateTime::currentDateTime().toTime_t() - _idleTimeSet.toTime_t() > 1200)
+    if ((QDateTime::currentDateTime().toMSecsSinceEpoch() - _idleTimeSet.toMSecsSinceEpoch()) > 1200000) {
+        // 20 * 60 * 1000 = 1200000
+        // 20 minutes have elapsed, clear the known idle time as it's likely inaccurate by now
         _idleTime = QDateTime();
+    }
     return _idleTime;
 }
 
-
 QStringList IrcUser::channels() const
 {
     QStringList chanList;
-    IrcChannel *channel;
-    foreach(channel, _channels) {
+    IrcChannelchannel;
+    foreach (channel, _channels) {
         chanList << channel->name();
     }
     return chanList;
 }
 
-
-void IrcUser::setCodecForEncoding(const QString &name)
+void IrcUser::setCodecForEncoding(const QString& name)
 {
-    setCodecForEncoding(QTextCodec::codecForName(name.toAscii()));
+    setCodecForEncoding(QTextCodec::codecForName(name.toLatin1()));
 }
 
-
-void IrcUser::setCodecForEncoding(QTextCodec *codec)
+void IrcUser::setCodecForEncoding(QTextCodec* codec)
 {
     _codecForEncoding = codec;
 }
 
-
-void IrcUser::setCodecForDecoding(const QString &name)
+void IrcUser::setCodecForDecoding(const QString& name)
 {
-    setCodecForDecoding(QTextCodec::codecForName(name.toAscii()));
+    setCodecForDecoding(QTextCodec::codecForName(name.toLatin1()));
 }
 
-
-void IrcUser::setCodecForDecoding(QTextCodec *codec)
+void IrcUser::setCodecForDecoding(QTextCodec* codec)
 {
     _codecForDecoding = codec;
 }
 
-
-QString IrcUser::decodeString(const QByteArray &text) const
+QString IrcUser::decodeString(const QByteArray& text) const
 {
-    if (!codecForDecoding()) return network()->decodeString(text);
+    if (!codecForDecoding())
+        return network()->decodeString(text);
     return ::decodeString(text, codecForDecoding());
 }
 
-
-QByteArray IrcUser::encodeString(const QString &string) const
+QByteArray IrcUser::encodeString(const QString& string) const
 {
     if (codecForEncoding()) {
         return codecForEncoding()->fromUnicode(string);
@@ -123,11 +117,10 @@ QByteArray IrcUser::encodeString(const QString &string) const
     return network()->encodeString(string);
 }
 
-
 // ====================
 //  PUBLIC SLOTS:
 // ====================
-void IrcUser::setUser(const QString &user)
+void IrcUser::setUser(const QStringuser)
 {
     if (!user.isEmpty() && _user != user) {
         _user = user;
@@ -135,8 +128,7 @@ void IrcUser::setUser(const QString &user)
     }
 }
 
-
-void IrcUser::setRealName(const QString &realName)
+void IrcUser::setRealName(const QString& realName)
 {
     if (!realName.isEmpty() && _realName != realName) {
         _realName = realName;
@@ -144,27 +136,34 @@ void IrcUser::setRealName(const QString &realName)
     }
 }
 
+void IrcUser::setAccount(const QString& account)
+{
+    if (_account != account) {
+        _account = account;
+        SYNC(ARG(account))
+    }
+}
 
-void IrcUser::setAway(const bool &away)
+void IrcUser::setAway(bool away)
 {
     if (away != _away) {
         _away = away;
+        markAwayChanged();
         SYNC(ARG(away))
         emit awaySet(away);
     }
 }
 
-
-void IrcUser::setAwayMessage(const QString &awayMessage)
+void IrcUser::setAwayMessage(const QString& awayMessage)
 {
     if (!awayMessage.isEmpty() && _awayMessage != awayMessage) {
         _awayMessage = awayMessage;
+        markAwayChanged();
         SYNC(ARG(awayMessage))
     }
 }
 
-
-void IrcUser::setIdleTime(const QDateTime &idleTime)
+void IrcUser::setIdleTime(const QDateTime& idleTime)
 {
     if (idleTime.isValid() && _idleTime != idleTime) {
         _idleTime = idleTime;
@@ -173,8 +172,7 @@ void IrcUser::setIdleTime(const QDateTime &idleTime)
     }
 }
 
-
-void IrcUser::setLoginTime(const QDateTime &loginTime)
+void IrcUser::setLoginTime(const QDateTime& loginTime)
 {
     if (loginTime.isValid() && _loginTime != loginTime) {
         _loginTime = loginTime;
@@ -182,8 +180,7 @@ void IrcUser::setLoginTime(const QDateTime &loginTime)
     }
 }
 
-
-void IrcUser::setServer(const QString &server)
+void IrcUser::setServer(const QString& server)
 {
     if (!server.isEmpty() && _server != server) {
         _server = server;
@@ -191,8 +188,7 @@ void IrcUser::setServer(const QString &server)
     }
 }
 
-
-void IrcUser::setIrcOperator(const QString &ircOperator)
+void IrcUser::setIrcOperator(const QString& ircOperator)
 {
     if (!ircOperator.isEmpty() && _ircOperator != ircOperator) {
         _ircOperator = ircOperator;
@@ -200,17 +196,30 @@ void IrcUser::setIrcOperator(const QString &ircOperator)
     }
 }
 
+// This function is only ever called by SYNC calls from legacy cores (pre-0.13).
+// Therefore, no SYNC call is needed here.
+void IrcUser::setLastAwayMessage(int lastAwayMessage)
+{
+#if QT_VERSION >= 0x050800
+    QDateTime lastAwayMessageTime = QDateTime::fromSecsSinceEpoch(lastAwayMessage);
+#else
+    // toSecsSinceEpoch() was added in Qt 5.8.  Manually downconvert to seconds for now.
+    // See https://doc.qt.io/qt-5/qdatetime.html#toMSecsSinceEpoch
+    QDateTime lastAwayMessageTime = QDateTime::fromMSecsSinceEpoch(lastAwayMessage * 1000);
+#endif
+    lastAwayMessageTime.setTimeSpec(Qt::UTC);
+    setLastAwayMessageTime(lastAwayMessageTime);
+}
 
-void IrcUser::setLastAwayMessage(const int &lastAwayMessage)
+void IrcUser::setLastAwayMessageTime(const QDateTime& lastAwayMessageTime)
 {
-    if (lastAwayMessage > _lastAwayMessage) {
-        _lastAwayMessage = lastAwayMessage;
-        SYNC(ARG(lastAwayMessage))
+    if (lastAwayMessageTime > _lastAwayMessageTime) {
+        _lastAwayMessageTime = lastAwayMessageTime;
+        SYNC(ARG(lastAwayMessageTime))
     }
 }
 
-
-void IrcUser::setHost(const QString &host)
+void IrcUser::setHost(const QString& host)
 {
     if (!host.isEmpty() && _host != host) {
         _host = host;
@@ -218,8 +227,7 @@ void IrcUser::setHost(const QString &host)
     }
 }
 
-
-void IrcUser::setNick(const QString &nick)
+void IrcUser::setNick(const QString& nick)
 {
     if (!nick.isEmpty() && nick != _nick) {
         _nick = nick;
@@ -229,8 +237,7 @@ void IrcUser::setNick(const QString &nick)
     }
 }
 
-
-void IrcUser::setWhoisServiceReply(const QString &whoisServiceReply)
+void IrcUser::setWhoisServiceReply(const QString& whoisServiceReply)
 {
     if (!whoisServiceReply.isEmpty() && whoisServiceReply != _whoisServiceReply) {
         _whoisServiceReply = whoisServiceReply;
@@ -238,8 +245,7 @@ void IrcUser::setWhoisServiceReply(const QString &whoisServiceReply)
     }
 }
 
-
-void IrcUser::setSuserHost(const QString &suserHost)
+void IrcUser::setSuserHost(const QString& suserHost)
 {
     if (!suserHost.isEmpty() && suserHost != _suserHost) {
         _suserHost = suserHost;
@@ -247,14 +253,19 @@ void IrcUser::setSuserHost(const QString &suserHost)
     }
 }
 
+void IrcUser::setEncrypted(bool encrypted)
+{
+    _encrypted = encrypted;
+    emit encryptedSet(encrypted);
+    SYNC(ARG(encrypted))
+}
 
 void IrcUser::updateObjectName()
 {
-    renameObject(QString::number(network()->networkId().toInt()) + "/" + _nick);
+    setObjectName(QString::number(network()->networkId().toInt()) + "/" + _nick);
 }
 
-
-void IrcUser::updateHostmask(const QString &mask)
+void IrcUser::updateHostmask(const QString& mask)
 {
     if (mask == hostmask())
         return;
@@ -265,41 +276,30 @@ void IrcUser::updateHostmask(const QString &mask)
     setHost(host);
 }
 
-
-void IrcUser::joinChannel(IrcChannel *channel)
+void IrcUser::joinChannel(IrcChannel* channel, bool skip_channel_join)
 {
     Q_ASSERT(channel);
     if (!_channels.contains(channel)) {
         _channels.insert(channel);
-        channel->joinIrcUser(this);
+        if (!skip_channel_join)
+            channel->joinIrcUser(this);
     }
 }
 
-
-void IrcUser::joinChannel(const QString &channelname)
+void IrcUser::joinChannel(const QString& channelname)
 {
     joinChannel(network()->newIrcChannel(channelname));
 }
 
-
-void IrcUser::partChannel(IrcChannel *channel)
+void IrcUser::partChannel(IrcChannel* channel)
 {
-    if (_channels.contains(channel)) {
-        _channels.remove(channel);
-        disconnect(channel, 0, this, 0);
-        channel->part(this);
-        QString channelName = channel->name();
-        SYNC_OTHER(partChannel, ARG(channelName))
-        if (_channels.isEmpty() && !network()->isMe(this))
-            quit();
-    }
+    partChannelInternal(channel, false);
 }
 
-
-void IrcUser::partChannel(const QString &channelname)
+void IrcUser::partChannel(const QString& channelname)
 {
-    IrcChannel *channel = network()->ircChannel(channelname);
-    if (channel == 0) {
+    IrcChannelchannel = network()->ircChannel(channelname);
+    if (channel == nullptr) {
         qWarning() << "IrcUser::partChannel(): received part for unknown Channel" << channelname;
     }
     else {
@@ -307,25 +307,41 @@ void IrcUser::partChannel(const QString &channelname)
     }
 }
 
+void IrcUser::partChannelInternal(IrcChannel* channel, bool skip_sync)
+{
+    if (_channels.contains(channel)) {
+        _channels.remove(channel);
+        disconnect(channel, nullptr, this, nullptr);
+        channel->part(this);
+        QString channelName = channel->name();
+        if (!skip_sync) SYNC_OTHER(partChannel, ARG(channelName))
+        if (_channels.isEmpty() && !network()->isMe(this))
+            quitInternal(skip_sync);
+    }
+}
 
 void IrcUser::quit()
 {
-    QList<IrcChannel *> channels = _channels.toList();
+    quitInternal(false);
+}
+
+void IrcUser::quitInternal(bool skip_sync)
+{
+    QList<IrcChannel*> channels = _channels.values();
     _channels.clear();
-    foreach(IrcChannel *channel, channels) {
-        disconnect(channel, 0, this, 0);
+    foreach (IrcChannel* channel, channels) {
+        disconnect(channel, nullptr, this, nullptr);
         channel->part(this);
     }
     network()->removeIrcUser(this);
-    SYNC(NO_ARG)
+    if (!skip_sync) SYNC(NO_ARG)
     emit quited();
 }
 
-
 void IrcUser::channelDestroyed()
 {
     // private slot!
-    IrcChannel *channel = static_cast<IrcChannel *>(sender());
+    auto* channel = static_cast<IrcChannel*>(sender());
     if (_channels.contains(channel)) {
         _channels.remove(channel);
         if (_channels.isEmpty() && !network()->isMe(this))
@@ -333,31 +349,36 @@ void IrcUser::channelDestroyed()
     }
 }
 
-
-void IrcUser::setUserModes(const QString &modes)
+void IrcUser::setUserModes(const QString& modes)
 {
-    _userModes = modes;
-    SYNC(ARG(modes))
-    emit userModesSet(modes);
+    if (_userModes != modes) {
+        _userModes = modes;
+        SYNC(ARG(modes))
+        emit userModesSet(modes);
+    }
 }
 
-
-void IrcUser::addUserModes(const QString &modes)
+void IrcUser::addUserModes(const QString& modes)
 {
     if (modes.isEmpty())
         return;
 
+    // Don't needlessly sync when no changes are made
+    bool changesMade = false;
     for (int i = 0; i < modes.count(); i++) {
-        if (!_userModes.contains(modes[i]))
+        if (!_userModes.contains(modes[i])) {
             _userModes += modes[i];
+            changesMade = true;
+        }
     }
 
-    SYNC(ARG(modes))
-    emit userModesAdded(modes);
+    if (changesMade) {
+        SYNC(ARG(modes))
+        emit userModesAdded(modes);
+    }
 }
 
-
-void IrcUser::removeUserModes(const QString &modes)
+void IrcUser::removeUserModes(const QString& modes)
 {
     if (modes.isEmpty())
         return;
@@ -369,15 +390,13 @@ void IrcUser::removeUserModes(const QString &modes)
     emit userModesRemoved(modes);
 }
 
-
-void IrcUser::setLastChannelActivity(BufferId buffer, const QDateTime &time)
+void IrcUser::setLastChannelActivity(BufferId buffer, const QDateTime& time)
 {
     _lastActivity[buffer] = time;
     emit lastChannelActivityUpdated(buffer, time);
 }
 
-
-void IrcUser::setLastSpokenTo(BufferId buffer, const QDateTime &time)
+void IrcUser::setLastSpokenTo(BufferId buffer, const QDateTime& time)
 {
     _lastSpokenTo[buffer] = time;
     emit lastSpokenToUpdated(buffer, time);