X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=blobdiff_plain;f=src%2Fcore%2Fcoresession.cpp;h=2ca9627ccd0e0d24f8ac0f55e928b84813eb8873;hp=fb0aad8ef54c038d5621d88e9373dd87a9695853;hb=dd69349ca91776432a4a53aa4d18dd8ef018cd26;hpb=4a5065255e652dd0c301bac0db41b7afb777ef49 diff --git a/src/core/coresession.cpp b/src/core/coresession.cpp index fb0aad8e..2ca9627c 100644 --- a/src/core/coresession.cpp +++ b/src/core/coresession.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2005-2013 by the Quassel Project * + * Copyright (C) 2005-2016 by the Quassel Project * * devel@quassel-irc.org * * * * This program is free software; you can redistribute it and/or modify * @@ -27,6 +27,7 @@ #include "corebuffersyncer.h" #include "corebacklogmanager.h" #include "corebufferviewmanager.h" +#include "coredccconfig.h" #include "coreeventmanager.h" #include "coreidentity.h" #include "coreignorelistmanager.h" @@ -34,19 +35,20 @@ #include "corenetwork.h" #include "corenetworkconfig.h" #include "coresessioneventprocessor.h" +#include "coretransfermanager.h" #include "coreusersettings.h" #include "ctcpparser.h" #include "eventstringifier.h" -#include "internalconnection.h" +#include "internalpeer.h" #include "ircchannel.h" #include "ircparser.h" #include "ircuser.h" #include "logger.h" #include "messageevent.h" +#include "remotepeer.h" #include "storage.h" #include "util.h" -#include "protocols/legacy/legacyconnection.h" class ProcessMessagesEvent : public QEvent { @@ -63,9 +65,11 @@ CoreSession::CoreSession(UserId uid, bool restoreState, QObject *parent) _bufferSyncer(new CoreBufferSyncer(this)), _backlogManager(new CoreBacklogManager(this)), _bufferViewManager(new CoreBufferViewManager(_signalProxy, this)), + _dccConfig(new CoreDccConfig(this)), _ircListHelper(new CoreIrcListHelper(this)), _networkConfig(new CoreNetworkConfig("GlobalNetworkConfig", this)), _coreInfo(this), + _transferManager(new CoreTransferManager(this)), _eventManager(new CoreEventManager(this)), _eventStringifier(new EventStringifier(this)), _sessionEventProcessor(new CoreSessionEventProcessor(this)), @@ -79,7 +83,7 @@ CoreSession::CoreSession(UserId uid, bool restoreState, QObject *parent) p->setHeartBeatInterval(30); p->setMaxHeartBeatCount(60); // 30 mins until we throw a dead socket out - connect(p, SIGNAL(peerRemoved(SignalProxy::AbstractPeer*)), SLOT(removeClient(SignalProxy::AbstractPeer*))); + connect(p, SIGNAL(peerRemoved(Peer*)), SLOT(removeClient(Peer*))); connect(p, SIGNAL(connected()), SLOT(clientsConnected())); connect(p, SIGNAL(disconnected()), SLOT(clientsDisconnected())); @@ -98,6 +102,9 @@ CoreSession::CoreSession(UserId uid, bool restoreState, QObject *parent) p->attachSlot(SIGNAL(createNetwork(const NetworkInfo &, const QStringList &)), this, SLOT(createNetwork(const NetworkInfo &, const QStringList &))); p->attachSlot(SIGNAL(removeNetwork(NetworkId)), this, SLOT(removeNetwork(NetworkId))); + p->attachSlot(SIGNAL(changePassword(PeerPtr,QString,QString,QString)), this, SLOT(changePassword(PeerPtr,QString,QString,QString))); + p->attachSignal(this, SIGNAL(passwordChanged(PeerPtr,bool))); + loadSettings(); initScriptEngine(); @@ -116,10 +123,12 @@ CoreSession::CoreSession(UserId uid, bool restoreState, QObject *parent) p->synchronize(_bufferSyncer); p->synchronize(&aliasManager()); p->synchronize(_backlogManager); + p->synchronize(dccConfig()); p->synchronize(ircListHelper()); p->synchronize(networkConfig()); p->synchronize(&_coreInfo); p->synchronize(&_ignoreListManager); + p->synchronize(transferManager()); // Restore session state if (restoreState) restoreSessionState(); @@ -131,7 +140,47 @@ CoreSession::CoreSession(UserId uid, bool restoreState, QObject *parent) CoreSession::~CoreSession() { 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); + } + } + + // 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(); + 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; } } @@ -169,7 +218,7 @@ void CoreSession::loadSettings() networkIter = networkInfos.erase(networkIter); } else { - networkIter++; + ++networkIter; } } s.removeIdentity(id); @@ -206,28 +255,25 @@ void CoreSession::restoreSessionState() } -void CoreSession::addClient(RemoteConnection *connection) +void CoreSession::addClient(RemotePeer *peer) { - QVariantMap reply; - reply["MsgType"] = "SessionInit"; - reply["SessionState"] = sessionState(); - connection->writeSocketData(reply); - signalProxy()->addPeer(connection); + peer->dispatch(sessionState()); + signalProxy()->addPeer(peer); } -void CoreSession::addClient(InternalConnection *connection) +void CoreSession::addClient(InternalPeer *peer) { - signalProxy()->addPeer(connection); + signalProxy()->addPeer(peer); emit sessionState(sessionState()); } -void CoreSession::removeClient(SignalProxy::AbstractPeer *peer) +void CoreSession::removeClient(Peer *peer) { - RemoteConnection *connection = qobject_cast(peer); - if (connection) - quInfo() << qPrintable(tr("Client")) << connection->description() << qPrintable(tr("disconnected (UserId: %1).").arg(user().toInt())); + RemotePeer *p = qobject_cast(peer); + if (p) + quInfo() << qPrintable(tr("Client")) << p->description() << qPrintable(tr("disconnected (UserId: %1).").arg(user().toInt())); } @@ -321,8 +367,8 @@ void CoreSession::processMessages() bufferInfo = Core::bufferInfo(user(), rawMsg.networkId, BufferInfo::StatusBuffer, ""); } Message msg(bufferInfo, rawMsg.type, rawMsg.text, rawMsg.sender, rawMsg.flags); - Core::storeMessage(msg); - emit displayMsg(msg); + if(Core::storeMessage(msg)) + emit displayMsg(msg); } else { QHash > bufferInfoCache; @@ -350,7 +396,7 @@ void CoreSession::processMessages() // recheck if there exists a buffer to store a redirected message in for (int i = 0; i < redirectedMessages.count(); i++) { - const RawMessage &rawMsg = _messageQueue.at(i); + const RawMessage &rawMsg = redirectedMessages.at(i); if (bufferInfoCache.contains(rawMsg.networkId) && bufferInfoCache[rawMsg.networkId].contains(rawMsg.target)) { bufferInfo = bufferInfoCache[rawMsg.networkId][rawMsg.target]; } @@ -364,10 +410,11 @@ void CoreSession::processMessages() messages << msg; } - Core::storeMessages(messages); - // FIXME: extend protocol to a displayMessages(MessageList) - for (int i = 0; i < messages.count(); i++) { - emit displayMsg(messages[i]); + if(Core::storeMessages(messages)) { + // FIXME: extend protocol to a displayMessages(MessageList) + for (int i = 0; i < messages.count(); i++) { + emit displayMsg(messages[i]); + } } } _processMessages = false; @@ -375,34 +422,20 @@ void CoreSession::processMessages() } -QVariant CoreSession::sessionState() +Protocol::SessionState CoreSession::sessionState() const { - QVariantMap v; - - v["CoreFeatures"] = (int)Quassel::features(); - - QVariantList bufs; - foreach(BufferInfo id, buffers()) bufs << qVariantFromValue(id); - v["BufferInfos"] = bufs; - QVariantList networkids; - foreach(NetworkId id, _networks.keys()) networkids << qVariantFromValue(id); - v["NetworkIds"] = networkids; - - quint32 ircusercount = 0; - quint32 ircchannelcount = 0; - foreach(Network *net, _networks.values()) { - ircusercount += net->ircUserCount(); - ircchannelcount += net->ircChannelCount(); - } - v["IrcUserCount"] = ircusercount; - v["IrcChannelCount"] = ircchannelcount; + QVariantList bufferInfos; + QVariantList networkIds; + QVariantList identities; - QList idlist; - foreach(Identity *i, _identities.values()) idlist << qVariantFromValue(*i); - v["Identities"] = idlist; + foreach(const BufferInfo &id, buffers()) + bufferInfos << QVariant::fromValue(id); + foreach(const NetworkId &id, _networks.keys()) + networkIds << QVariant::fromValue(id); + foreach(const Identity *i, _identities.values()) + identities << QVariant::fromValue(*i); - //v["Payload"] = QByteArray(100000000, 'a'); // for testing purposes - return v; + return Protocol::SessionState(identities, bufferInfos, networkIds); } @@ -558,7 +591,7 @@ void CoreSession::destroyNetwork(NetworkId id) messageIter = _messageQueue.erase(messageIter); } else { - messageIter++; + ++messageIter; } } // remove buffers from syncer @@ -588,7 +621,7 @@ void CoreSession::clientsConnected() IrcUser *me = 0; while (netIter != _networks.end()) { net = *netIter; - netIter++; + ++netIter; if (!net->isConnected()) continue; @@ -615,7 +648,7 @@ void CoreSession::clientsDisconnected() QString awayReason; while (netIter != _networks.end()) { net = *netIter; - netIter++; + ++netIter; if (!net->isConnected()) continue; @@ -631,23 +664,34 @@ void CoreSession::clientsDisconnected() if (!identity->detachAwayReason().isEmpty()) awayReason = identity->detachAwayReason(); net->setAutoAwayActive(true); + // Allow handleAway() to format the current date/time in the string. net->userInputHandler()->handleAway(BufferInfo(), awayReason); } } } -void CoreSession::globalAway(const QString &msg) +void CoreSession::globalAway(const QString &msg, const bool skipFormatting) { QHash::iterator netIter = _networks.begin(); CoreNetwork *net = 0; while (netIter != _networks.end()) { net = *netIter; - netIter++; + ++netIter; if (!net->isConnected()) continue; - net->userInputHandler()->issueAway(msg, false /* no force away */); + net->userInputHandler()->issueAway(msg, false /* no force away */, skipFormatting); } } + +void CoreSession::changePassword(PeerPtr peer, const QString &userName, const QString &oldPassword, const QString &newPassword) +{ + bool success = false; + UserId uid = Core::validateUser(userName, oldPassword); + if (uid.isValid() && uid == user()) + success = Core::changeUserPassword(uid, newPassword); + + emit passwordChanged(peer, success); +}