#include "ircchannel.h"
#include "ircparser.h"
#include "ircuser.h"
-#include "logger.h"
+#include "logmessage.h"
#include "messageevent.h"
#include "remotepeer.h"
#include "storage.h"
p->setHeartBeatInterval(30);
p->setMaxHeartBeatCount(60); // 30 mins until we throw a dead socket out
- connect(p, SIGNAL(peerRemoved(Peer*)), SLOT(removeClient(Peer*)));
+ connect(p, &SignalProxy::peerRemoved, this, &CoreSession::removeClient);
- connect(p, SIGNAL(connected()), SLOT(clientsConnected()));
- connect(p, SIGNAL(disconnected()), SLOT(clientsDisconnected()));
+ connect(p, &SignalProxy::connected, this, &CoreSession::clientsConnected);
+ connect(p, &SignalProxy::disconnected, this, &CoreSession::clientsDisconnected);
p->attachSlot(SIGNAL(sendInput(BufferInfo, QString)), this, SLOT(msgFromClient(BufferInfo, QString)));
p->attachSignal(this, SIGNAL(displayMsg(Message)));
eventManager()->registerObject(ctcpParser(), EventManager::LowPriority, "send");
// periodically save our session state
- connect(Core::instance()->syncTimer(), SIGNAL(timeout()), this, SLOT(saveSessionState()));
+ connect(Core::instance()->syncTimer(), &QTimer::timeout, this, &CoreSession::saveSessionState);
p->synchronize(_bufferSyncer);
p->synchronize(&aliasManager());
p->synchronize(_coreInfo);
p->synchronize(&_ignoreListManager);
p->synchronize(&_highlightRuleManager);
+ // Listen to network removed events
+ connect(this, &CoreSession::networkRemoved,
+ &_highlightRuleManager, &HighlightRuleManager::networkRemoved);
p->synchronize(transferManager());
// Restore session state
if (restoreState)
}
-CoreSession::~CoreSession()
+void CoreSession::shutdown()
{
saveSessionState();
- /* Why partially duplicate CoreNetwork destructor? When each CoreNetwork quits in the
- * destructor, disconnections are processed in sequence for each object. For many IRC servers
- * on a slow network, this could significantly delay core shutdown [msecs wait * network count].
- *
- * Here, CoreSession first calls disconnect on all networks, letting them all start
- * disconnecting before beginning to sequentially wait for each network. Ideally, after the
- * first network is disconnected, the other networks will have already closed. Worst-case may
- * still wait [msecs wait time * num. of networks], but the risk should be much lower.
- *
- * CoreNetwork should still do cleanup in its own destructor in case a network is deleted
- * outside of deleting the whole CoreSession.
- *
- * If this proves to be problematic in the future, there's an alternative Qt signal-based system
- * implemented in another pull request that guarentees a maximum amount of time to disconnect,
- * but at the cost of more complex code.
- *
- * See https://github.com/quassel/quassel/pull/203
- */
-
- foreach(CoreNetwork *net, _networks.values()) {
- // Request each network properly disconnect, but don't count as user-requested disconnect
- if (net->socketConnected()) {
- // Only try if the socket's fully connected (not initializing or disconnecting).
- // Force an immediate disconnect, jumping the command queue. Ensures the proper QUIT is
- // shown even if other messages are queued.
- net->disconnectFromIrc(false, QString(), false, true);
+ // Request disconnect from all connected networks in parallel, and wait until every network
+ // has emitted the disconnected() signal before deleting the session itself
+ for (CoreNetwork *net : _networks.values()) {
+ if (net->socketState() != QAbstractSocket::UnconnectedState) {
+ _networksPendingDisconnect.insert(net->networkId());
+ connect(net, SIGNAL(disconnected(NetworkId)), this, SLOT(onNetworkDisconnected(NetworkId)));
+ net->shutdown();
}
}
- // Process the putCmd events that trigger the quit. Without this, shutting down the core
- // results in abrubtly closing the socket rather than sending the QUIT as expected.
- QCoreApplication::processEvents();
+ if (_networksPendingDisconnect.isEmpty()) {
+ // Nothing to do, suicide so the core can shut down
+ deleteLater();
+ }
+}
- foreach(CoreNetwork *net, _networks.values()) {
- // Wait briefly for each network to disconnect. Sometimes it takes a little while to send.
- if (!net->forceDisconnect()) {
- qWarning() << "Timed out quitting network" << net->networkName() <<
- "(user ID " << net->userId() << ")";
- }
- // Delete the network now that it's closed
- delete net;
+
+void CoreSession::onNetworkDisconnected(NetworkId networkId)
+{
+ _networksPendingDisconnect.remove(networkId);
+ if (_networksPendingDisconnect.isEmpty()) {
+ // We're done, suicide so the core can shut down
+ deleteLater();
}
}
CoreNetwork *CoreSession::network(NetworkId id) const
{
if (_networks.contains(id)) return _networks[id];
- return 0;
+ return nullptr;
}
CoreIdentity *CoreSession::identity(IdentityId id) const
{
if (_identities.contains(id)) return _identities[id];
- return 0;
+ return nullptr;
}
void CoreSession::restoreSessionState()
{
QList<NetworkId> nets = Core::connectedNetworks(user());
- CoreNetwork *net = 0;
+ CoreNetwork *net = nullptr;
foreach(NetworkId id, nets) {
net = network(id);
Q_ASSERT(net);
void CoreSession::removeClient(Peer *peer)
{
- RemotePeer *p = qobject_cast<RemotePeer *>(peer);
+ auto *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());
if (_ignoreListManager.match(rawMsg, networkName) == IgnoreListManager::HardStrictness)
return;
- if (_highlightRuleManager.match(rawMsg, currentNetwork->myNick(), currentNetwork->identityPtr()->nicks()))
+
+ if (currentNetwork && _highlightRuleManager.match(rawMsg, currentNetwork->myNick(), currentNetwork->identityPtr()->nicks()))
rawMsg.flags |= Message::Flag::Highlight;
_messageQueue << rawMsg;
void CoreSession::recvStatusMsgFromServer(QString msg)
{
- CoreNetwork *net = qobject_cast<CoreNetwork *>(sender());
+ auto *net = qobject_cast<CoreNetwork *>(sender());
Q_ASSERT(net);
emit displayStatusMsg(net->networkName(), msg);
}
void CoreSession::createIdentity(const CoreIdentity &identity)
{
- CoreIdentity *coreIdentity = new CoreIdentity(identity, this);
+ auto *coreIdentity = new CoreIdentity(identity, this);
_identities[identity.id()] = coreIdentity;
// CoreIdentity has its own synchronize method since its "private" sslManager needs to be synced as well
coreIdentity->synchronize(signalProxy());
- connect(coreIdentity, SIGNAL(updated()), this, SLOT(updateIdentityBySender()));
+ connect(coreIdentity, &SyncableObject::updated, this, &CoreSession::updateIdentityBySender);
emit identityCreated(*coreIdentity);
}
void CoreSession::updateIdentityBySender()
{
- CoreIdentity *identity = qobject_cast<CoreIdentity *>(sender());
+ auto *identity = qobject_cast<CoreIdentity *>(sender());
if (!identity)
return;
Core::updateIdentity(user(), *identity);
id = info.networkId.toInt();
if (!_networks.contains(id)) {
// create persistent chans
- QRegExp rx("\\s*(\\S+)(?:\\s*(\\S+))?\\s*");
+ QRegExp rx(R"(\s*(\S+)(?:\s*(\S+))?\s*)");
foreach(QString channel, persistentChans) {
if (!rx.exactMatch(channel)) {
qWarning() << QString("Invalid persistent channel declaration: %1").arg(channel);
CoreNetwork *net = new CoreNetwork(id, this);
connect(net, SIGNAL(displayMsg(NetworkId, Message::Type, BufferInfo::Type, const QString &, const QString &, const QString &, Message::Flags)),
SLOT(recvMessageFromServer(NetworkId, Message::Type, BufferInfo::Type, const QString &, const QString &, const QString &, Message::Flags)));
- connect(net, SIGNAL(displayStatusMsg(QString)), SLOT(recvStatusMsgFromServer(QString)));
- connect(net, SIGNAL(disconnected(NetworkId)), SIGNAL(networkDisconnected(NetworkId)));
+ connect(net, &CoreNetwork::displayStatusMsg, this, &CoreSession::recvStatusMsgFromServer);
+ connect(net, &CoreNetwork::disconnected, this, &CoreSession::networkDisconnected);
net->setNetworkInfo(info);
net->setProxy(signalProxy());
if (net->connectionState() != Network::Disconnected) {
// make sure we no longer receive data from the tcp buffer
- disconnect(net, SIGNAL(displayMsg(NetworkId, Message::Type, BufferInfo::Type, const QString &, const QString &, const QString &, Message::Flags)), this, 0);
- disconnect(net, SIGNAL(displayStatusMsg(QString)), this, 0);
- connect(net, SIGNAL(disconnected(NetworkId)), this, SLOT(destroyNetwork(NetworkId)));
+ disconnect(net, SIGNAL(displayMsg(NetworkId, Message::Type, BufferInfo::Type, const QString &, const QString &, const QString &, Message::Flags)), this, nullptr);
+ disconnect(net, SIGNAL(displayStatusMsg(QString)), this, nullptr);
+ connect(net, &CoreNetwork::disconnected, this, &CoreSession::destroyNetwork);
net->disconnectFromIrc();
}
else {
void CoreSession::clientsConnected()
{
QHash<NetworkId, CoreNetwork *>::iterator netIter = _networks.begin();
- Identity *identity = 0;
- CoreNetwork *net = 0;
- IrcUser *me = 0;
+ Identity *identity = nullptr;
+ CoreNetwork *net = nullptr;
+ IrcUser *me = nullptr;
while (netIter != _networks.end()) {
net = *netIter;
++netIter;
void CoreSession::clientsDisconnected()
{
QHash<NetworkId, CoreNetwork *>::iterator netIter = _networks.begin();
- Identity *identity = 0;
- CoreNetwork *net = 0;
- IrcUser *me = 0;
+ Identity *identity = nullptr;
+ CoreNetwork *net = nullptr;
+ IrcUser *me = nullptr;
QString awayReason;
while (netIter != _networks.end()) {
net = *netIter;
void CoreSession::globalAway(const QString &msg, const bool skipFormatting)
{
QHash<NetworkId, CoreNetwork *>::iterator netIter = _networks.begin();
- CoreNetwork *net = 0;
+ CoreNetwork *net = nullptr;
while (netIter != _networks.end()) {
net = *netIter;
++netIter;