Automatically synchronize CoreInfo when on connect and disconnect
[quassel.git] / src / core / coresession.cpp
index 39bd69b..afaf48d 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  *
@@ -31,6 +31,7 @@
 #include "coreeventmanager.h"
 #include "coreidentity.h"
 #include "coreignorelistmanager.h"
+#include "coreinfo.h"
 #include "coreirclisthelper.h"
 #include "corenetwork.h"
 #include "corenetworkconfig.h"
@@ -68,7 +69,7 @@ CoreSession::CoreSession(UserId uid, bool restoreState, QObject *parent)
     _dccConfig(new CoreDccConfig(this)),
     _ircListHelper(new CoreIrcListHelper(this)),
     _networkConfig(new CoreNetworkConfig("GlobalNetworkConfig", this)),
-    _coreInfo(this),
+    _coreInfo(new CoreInfo(this)),
     _transferManager(new CoreTransferManager(this)),
     _eventManager(new CoreEventManager(this)),
     _eventStringifier(new EventStringifier(this)),
@@ -77,7 +78,8 @@ CoreSession::CoreSession(UserId uid, bool restoreState, QObject *parent)
     _ircParser(new IrcParser(this)),
     scriptEngine(new QScriptEngine(this)),
     _processMessages(false),
-    _ignoreListManager(this)
+    _ignoreListManager(this),
+    _highlightRuleManager(this)
 {
     SignalProxy *p = signalProxy();
     p->setHeartBeatInterval(30);
@@ -105,6 +107,16 @@ CoreSession::CoreSession(UserId uid, bool restoreState, QObject *parent)
     p->attachSlot(SIGNAL(changePassword(PeerPtr,QString,QString,QString)), this, SLOT(changePassword(PeerPtr,QString,QString,QString)));
     p->attachSignal(this, SIGNAL(passwordChanged(PeerPtr,bool)));
 
+    p->attachSlot(SIGNAL(kickClient(int)), this, SLOT(kickClient(int)));
+    p->attachSignal(this, SIGNAL(disconnectFromCore()));
+
+    QVariantMap data;
+    data["quasselVersion"] = Quassel::buildInfo().fancyVersionString;
+    data["quasselBuildDate"] = Quassel::buildInfo().commitDate; // "BuildDate" for compatibility
+    data["startTime"] = Core::instance()->startTime();
+    data["sessionConnectedClients"] = 0;
+    _coreInfo->setCoreData(data);
+
     loadSettings();
     initScriptEngine();
 
@@ -126,8 +138,9 @@ CoreSession::CoreSession(UserId uid, bool restoreState, QObject *parent)
     p->synchronize(dccConfig());
     p->synchronize(ircListHelper());
     p->synchronize(networkConfig());
-    p->synchronize(&_coreInfo);
+    p->synchronize(_coreInfo);
     p->synchronize(&_ignoreListManager);
+    p->synchronize(&_highlightRuleManager);
     p->synchronize(transferManager());
     // Restore session state
     if (restoreState)
@@ -257,8 +270,13 @@ void CoreSession::restoreSessionState()
 
 void CoreSession::addClient(RemotePeer *peer)
 {
+    signalProxy()->setTargetPeer(peer);
+
     peer->dispatch(sessionState());
     signalProxy()->addPeer(peer);
+    _coreInfo->setConnectedClientData(signalProxy()->peerCount(), signalProxy()->peerData());
+
+    signalProxy()->setTargetPeer(nullptr);
 }
 
 
@@ -274,6 +292,7 @@ void CoreSession::removeClient(Peer *peer)
     RemotePeer *p = qobject_cast<RemotePeer *>(peer);
     if (p)
         quInfo() << qPrintable(tr("Client")) << p->description() << qPrintable(tr("disconnected (UserId: %1).").arg(user().toInt()));
+    _coreInfo->setConnectedClientData(signalProxy()->peerCount(), signalProxy()->peerData());
 }
 
 
@@ -283,6 +302,17 @@ QHash<QString, QString> CoreSession::persistentChannels(NetworkId id) const
 }
 
 
+QHash<QString, QByteArray> CoreSession::bufferCiphers(NetworkId id) const
+{
+    return Core::bufferCiphers(user(), id);
+}
+
+void CoreSession::setBufferCipher(NetworkId id, const QString &bufferName, const QByteArray &cipher) const
+{
+    Core::setBufferCipher(user(), id, bufferName, cipher);
+}
+
+
 // FIXME switch to BufferId
 void CoreSession::msgFromClient(BufferInfo bufinfo, QString msg)
 {
@@ -314,6 +344,9 @@ void CoreSession::recvMessageFromServer(NetworkId networkId, Message::Type type,
     if (_ignoreListManager.match(rawMsg, networkName) == IgnoreListManager::HardStrictness)
         return;
 
+    if (_highlightRuleManager.match(rawMsg, currentNetwork->myNick(), currentNetwork->identityPtr()->nicks()))
+        rawMsg.flags |= Message::Flag::Highlight;
+
     _messageQueue << rawMsg;
     if (!_processMessages) {
         _processMessages = true;
@@ -366,7 +399,9 @@ void CoreSession::processMessages()
             Q_ASSERT(!createBuffer);
             bufferInfo = Core::bufferInfo(user(), rawMsg.networkId, BufferInfo::StatusBuffer, "");
         }
-        Message msg(bufferInfo, rawMsg.type, rawMsg.text, rawMsg.sender, rawMsg.flags);
+        Message msg(bufferInfo, rawMsg.type, rawMsg.text, rawMsg.sender, senderPrefixes(rawMsg.sender, bufferInfo),
+                    realName(rawMsg.sender, rawMsg.networkId),  avatarUrl(rawMsg.sender, rawMsg.networkId),
+                    rawMsg.flags);
         if(Core::storeMessage(msg))
             emit displayMsg(msg);
     }
@@ -390,7 +425,9 @@ void CoreSession::processMessages()
                 }
                 bufferInfoCache[rawMsg.networkId][rawMsg.target] = bufferInfo;
             }
-            Message msg(bufferInfo, rawMsg.type, rawMsg.text, rawMsg.sender, rawMsg.flags);
+            Message msg(bufferInfo, rawMsg.type, rawMsg.text, rawMsg.sender, senderPrefixes(rawMsg.sender, bufferInfo),
+                        realName(rawMsg.sender, rawMsg.networkId),  avatarUrl(rawMsg.sender, rawMsg.networkId),
+                        rawMsg.flags);
             messages << msg;
         }
 
@@ -406,7 +443,9 @@ void CoreSession::processMessages()
                 // add the StatusBuffer to the Cache in case there are more Messages for the original target
                 bufferInfoCache[rawMsg.networkId][rawMsg.target] = bufferInfo;
             }
-            Message msg(bufferInfo, rawMsg.type, rawMsg.text, rawMsg.sender, rawMsg.flags);
+            Message msg(bufferInfo, rawMsg.type, rawMsg.text, rawMsg.sender, senderPrefixes(rawMsg.sender, bufferInfo),
+                        realName(rawMsg.sender, rawMsg.networkId),  avatarUrl(rawMsg.sender, rawMsg.networkId),
+                        rawMsg.flags);
             messages << msg;
         }
 
@@ -421,6 +460,52 @@ void CoreSession::processMessages()
     _messageQueue.clear();
 }
 
+QString CoreSession::senderPrefixes(const QString &sender, const BufferInfo &bufferInfo) const
+{
+    CoreNetwork *currentNetwork = network(bufferInfo.networkId());
+    if (!currentNetwork) {
+        return {};
+    }
+
+    if (bufferInfo.type() != BufferInfo::ChannelBuffer) {
+        return {};
+    }
+
+    IrcChannel *currentChannel = currentNetwork->ircChannel(bufferInfo.bufferName());
+    if (!currentChannel) {
+        return {};
+    }
+
+    const QString modes = currentChannel->userModes(nickFromMask(sender).toLower());
+    return currentNetwork->modesToPrefixes(modes);
+}
+
+QString CoreSession::realName(const QString &sender, NetworkId networkId) const
+{
+    CoreNetwork *currentNetwork = network(networkId);
+    if (!currentNetwork) {
+        return {};
+    }
+
+    IrcUser *currentUser = currentNetwork->ircUser(nickFromMask(sender));
+    if (!currentUser) {
+        return {};
+    }
+
+    return currentUser->realName();
+}
+
+QString CoreSession::avatarUrl(const QString &sender, NetworkId networkId) const
+{
+    Q_UNUSED(sender);
+    Q_UNUSED(networkId);
+    // Currently we do not have a way to retrieve this value yet.
+    //
+    // This likely will require implementing IRCv3's METADATA spec.
+    // See https://ircv3.net/irc/
+    // And https://blog.irccloud.com/avatars/
+    return "";
+}
 
 Protocol::SessionState CoreSession::sessionState() const
 {
@@ -478,6 +563,9 @@ void CoreSession::createIdentity(const Identity &identity, const QVariantMap &ad
         createIdentity(coreIdentity);
 }
 
+const QString CoreSession::strictSysident() {
+    return Core::instance()->strictSysIdent(_user);
+}
 
 void CoreSession::createIdentity(const CoreIdentity &identity)
 {
@@ -662,8 +750,9 @@ void CoreSession::clientsDisconnected()
 
         if (identity->detachAwayEnabled() && !me->isAway()) {
             if (!identity->detachAwayReason().isEmpty())
-                awayReason = formatCurrentDateTimeInString(identity->detachAwayReason());
+                awayReason = identity->detachAwayReason();
             net->setAutoAwayActive(true);
+            // Allow handleAway() to format the current date/time in the string.
             net->userInputHandler()->handleAway(BufferInfo(), awayReason);
         }
     }
@@ -685,12 +774,26 @@ void CoreSession::globalAway(const QString &msg, const bool skipFormatting)
     }
 }
 
-void CoreSession::changePassword(PeerPtr peer, const QString &userName, const QString &oldPassword, const QString &newPassword)
-{
+void CoreSession::changePassword(PeerPtr peer, const QString &userName, const QString &oldPassword, const QString &newPassword) {
+    Q_UNUSED(peer);
+
     bool success = false;
     UserId uid = Core::validateUser(userName, oldPassword);
     if (uid.isValid() && uid == user())
         success = Core::changeUserPassword(uid, newPassword);
 
-    emit passwordChanged(peer, success);
+    signalProxy()->restrictTargetPeers(signalProxy()->sourcePeer(), [&]{
+        emit passwordChanged(nullptr, success);
+    });
+}
+
+void CoreSession::kickClient(int peerId) {
+    auto peer = signalProxy()->peerById(peerId);
+    if (peer == nullptr) {
+        qWarning() << "Invalid peer Id: " << peerId;
+        return;
+    }
+    signalProxy()->restrictTargetPeers(peer, [&]{
+        emit disconnectFromCore();
+    });
 }