X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=blobdiff_plain;f=src%2Fcore%2Fcorenetwork.cpp;h=5e2c3b1d6c0da7a8ff6f788137b2101106e2c6ec;hp=a5c40e622e14f4f9df5ca001b357e092bc25f265;hb=dc2aa39d20b60e7cd8e0ba66ca6c9ed729add008;hpb=a5dfcc8ecf8b81025d24b3c5c816169e3e030ea4 diff --git a/src/core/corenetwork.cpp b/src/core/corenetwork.cpp index a5c40e62..5e2c3b1d 100644 --- a/src/core/corenetwork.cpp +++ b/src/core/corenetwork.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2005-08 by the Quassel Project * + * Copyright (C) 2005-09 by the Quassel Project * * devel@quassel-irc.org * * * * This program is free software; you can redistribute it and/or modify * @@ -20,10 +20,9 @@ #include "corenetwork.h" - #include "core.h" #include "coresession.h" -#include "identity.h" +#include "coreidentity.h" #include "ircserverhandler.h" #include "userinputhandler.h" @@ -41,6 +40,8 @@ CoreNetwork::CoreNetwork(const NetworkId &networkid, CoreSession *session) _previousConnectionAttemptFailed(false), _lastUsedServerIndex(0), + _gotPong(true), + // TODO make autowho configurable (possibly per-network) _autoWhoEnabled(true), _autoWhoInterval(90), @@ -51,7 +52,7 @@ CoreNetwork::CoreNetwork(const NetworkId &networkid, CoreSession *session) _socketCloseTimer.setSingleShot(true); connect(&_socketCloseTimer, SIGNAL(timeout()), this, SLOT(socketCloseTimeout())); - _pingTimer.setInterval(60000); + _pingTimer.setInterval(30000); connect(&_pingTimer, SIGNAL(timeout()), this, SLOT(sendPing())); _autoWhoTimer.setInterval(_autoWhoDelay * 1000); @@ -69,16 +70,14 @@ CoreNetwork::CoreNetwork(const NetworkId &networkid, CoreSession *session) connect(this, SIGNAL(connectRequested()), this, SLOT(connectToIrc())); + connect(&socket, SIGNAL(connected()), this, SLOT(socketInitialized())); connect(&socket, SIGNAL(disconnected()), this, SLOT(socketDisconnected())); connect(&socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(socketError(QAbstractSocket::SocketError))); connect(&socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(socketStateChanged(QAbstractSocket::SocketState))); connect(&socket, SIGNAL(readyRead()), this, SLOT(socketHasData())); #ifdef HAVE_SSL - connect(&socket, SIGNAL(connected()), this, SLOT(sslSocketConnected())); connect(&socket, SIGNAL(encrypted()), this, SLOT(socketInitialized())); connect(&socket, SIGNAL(sslErrors(const QList &)), this, SLOT(sslErrors(const QList &))); -#else - connect(&socket, SIGNAL(connected()), this, SLOT(socketInitialized())); #endif } @@ -135,18 +134,22 @@ void CoreNetwork::connectToIrc(bool reconnecting) { qWarning() << "Server list empty, ignoring connect request!"; return; } - Identity *identity = identityPtr(); + CoreIdentity *identity = identityPtr(); if(!identity) { qWarning() << "Invalid identity configures, ignoring connect request!"; return; } + + // cleaning up old quit reason + _quitReason.clear(); + // use a random server? if(useRandomServer()) { _lastUsedServerIndex = qrand() % serverList().size(); } else if(_previousConnectionAttemptFailed) { // cycle to next server if previous connection attempt failed displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("Connection failed. Cycling to next Server")); - if(++_lastUsedServerIndex == serverList().size()) { + if(++_lastUsedServerIndex >= serverList().size()) { _lastUsedServerIndex = 0; } } @@ -155,27 +158,67 @@ void CoreNetwork::connectToIrc(bool reconnecting) { Server server = usedServer(); displayStatusMsg(tr("Connecting to %1:%2...").arg(server.host).arg(server.port)); displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("Connecting to %1:%2...").arg(server.host).arg(server.port)); + + if(server.useProxy) { + QNetworkProxy proxy((QNetworkProxy::ProxyType)server.proxyType, server.proxyHost, server.proxyPort, server.proxyUser, server.proxyPass); + socket.setProxy(proxy); + } else { + socket.setProxy(QNetworkProxy::NoProxy); + } + +#ifdef HAVE_SSL + socket.setProtocol((QSsl::SslProtocol)server.sslVersion); + if(server.useSsl) { + CoreIdentity *identity = identityPtr(); + if(identity) { + socket.setLocalCertificate(identity->sslCert()); + socket.setPrivateKey(identity->sslKey()); + } + socket.connectToHostEncrypted(server.host, server.port); + } else { + socket.connectToHost(server.host, server.port); + } +#else socket.connectToHost(server.host, server.port); +#endif } -void CoreNetwork::disconnectFromIrc(bool requested, const QString &reason) { +void CoreNetwork::disconnectFromIrc(bool requested, const QString &reason, bool withReconnect) { _quitRequested = requested; // see socketDisconnected(); - _autoReconnectTimer.stop(); - _autoReconnectCount = 0; // prohibiting auto reconnect + if(!withReconnect) { + _autoReconnectTimer.stop(); + _autoReconnectCount = 0; // prohibiting auto reconnect + } + + IrcUser *me_ = me(); + if(me_) { + QString awayMsg; + if(me_->isAway()) + awayMsg = me_->awayMessage(); + Core::setAwayMessage(userId(), networkId(), awayMsg); + Core::setUserModes(userId(), networkId(), me_->userModes()); + } + + if(reason.isEmpty() && identityPtr()) + _quitReason = identityPtr()->quitReason(); + else + _quitReason = reason; + displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("Disconnecting.")); - if(socket.state() == QAbstractSocket::UnconnectedState) { - socketDisconnected(); - } else if(socket.state() < QAbstractSocket::ConnectedState || !requested) { - // we might be in a state waiting for a timeout... - // or (!requested) this is a core shutdown... - // in both cases we don't really care... set a disconnected state - socket.close(); + switch(socket.state()) { + case QAbstractSocket::UnconnectedState: socketDisconnected(); - } else { - // quit gracefully if it's user requested quit - userInputHandler()->issueQuit(reason); - // the irc server has 10 seconds to close the socket - _socketCloseTimer.start(10000); + break; + case QAbstractSocket::ConnectedState: + userInputHandler()->issueQuit(_quitReason); + default: + if(!requested) { + socket.close(); + socketDisconnected(); + } else { + // the irc server has 10 seconds to close the socket + _socketCloseTimer.start(10000); + } } } @@ -253,7 +296,10 @@ void CoreNetwork::socketHasData() { } } -void CoreNetwork::socketError(QAbstractSocket::SocketError) { +void CoreNetwork::socketError(QAbstractSocket::SocketError error) { + if(_quitRequested && error == QAbstractSocket::RemoteHostClosedError) + return; + _previousConnectionAttemptFailed = true; qWarning() << qPrintable(tr("Could not connect to %1 (%2)").arg(networkName(), socket.errorString())); emit connectionError(socket.errorString()); @@ -264,17 +310,14 @@ void CoreNetwork::socketError(QAbstractSocket::SocketError) { } } +void CoreNetwork::socketInitialized() { + Server server = usedServer(); #ifdef HAVE_SSL -void CoreNetwork::sslSocketConnected() { - if(!usedServer().useSsl) - socketInitialized(); - else - socket.startClientEncryption(); -} + if(server.useSsl && !socket.isEncrypted()) + return; #endif -void CoreNetwork::socketInitialized() { - Identity *identity = identityPtr(); + CoreIdentity *identity = identityPtr(); if(!identity) { qCritical() << "Identity invalid!"; disconnectFromIrc(); @@ -287,9 +330,8 @@ void CoreNetwork::socketInitialized() { _tokenBucket = 5; // init with a full bucket _tokenBucketTimer.start(_messagesPerSecond * 1000); - QString passwd = usedServer().password; - if(!passwd.isEmpty()) { - putRawLine(serverEncode(QString("PASS %1").arg(passwd))); + if(!server.password.isEmpty()) { + putRawLine(serverEncode(QString("PASS %1").arg(server.password))); } putRawLine(serverEncode(QString("NICK :%1").arg(identity->nicks()[0]))); putRawLine(serverEncode(QString("USER %1 8 * :%2").arg(identity->ident(), identity->realName()))); @@ -297,6 +339,8 @@ void CoreNetwork::socketInitialized() { void CoreNetwork::socketDisconnected() { _pingTimer.stop(); + resetPong(); + _autoWhoCycleTimer.stop(); _autoWhoTimer.stop(); _autoWhoQueue.clear(); @@ -309,7 +353,7 @@ void CoreNetwork::socketDisconnected() { IrcUser *me_ = me(); if(me_) { foreach(QString channel, me_->channels()) - emit displayMsg(Message::Quit, BufferInfo::ChannelBuffer, channel, "", me_->hostmask()); + emit displayMsg(Message::Quit, BufferInfo::ChannelBuffer, channel, _quitReason, me_->hostmask()); } setConnected(false); @@ -351,14 +395,32 @@ void CoreNetwork::socketStateChanged(QAbstractSocket::SocketState socketState) { void CoreNetwork::networkInitialized() { setConnectionState(Network::Initialized); setConnected(true); + _quitRequested = false; if(useAutoReconnect()) { // reset counter _autoReconnectCount = autoReconnectRetries(); } + // restore away state + QString awayMsg = Core::awayMessage(userId(), networkId()); + if(!awayMsg.isEmpty()) + userInputHandler()->handleAway(BufferInfo(), Core::awayMessage(userId(), networkId())); + + // restore old user modes if server default mode is set. + IrcUser *me_ = me(); + if(me_) { + if(!me_->userModes().isEmpty()) { + restoreUserModes(); + } else { + connect(me_, SIGNAL(userModesSet(QString)), this, SLOT(restoreUserModes())); + connect(me_, SIGNAL(userModesAdded(QString)), this, SLOT(restoreUserModes())); + } + } + sendPerform(); + resetPong(); _pingTimer.start(); if(_autoWhoEnabled) { @@ -385,19 +447,42 @@ void CoreNetwork::sendPerform() { } // rejoin channels we've been in - QStringList channels, keys; - foreach(QString chan, persistentChannels()) { - QString key = channelKey(chan); - if(!key.isEmpty()) { - channels.prepend(chan); - keys.prepend(key); - } else { - channels.append(chan); + if(rejoinChannels()) { + QStringList channels, keys; + foreach(QString chan, coreSession()->persistentChannels(networkId()).keys()) { + QString key = channelKey(chan); + if(!key.isEmpty()) { + channels.prepend(chan); + keys.prepend(key); + } else { + channels.append(chan); + } } + QString joinString = QString("%1 %2").arg(channels.join(",")).arg(keys.join(",")).trimmed(); + if(!joinString.isEmpty()) + userInputHandler()->handleJoin(statusBuf, joinString); } - QString joinString = QString("%1 %2").arg(channels.join(",")).arg(keys.join(",")).trimmed(); - if(!joinString.isEmpty()) - userInputHandler()->handleJoin(statusBuf, joinString); +} + +void CoreNetwork::restoreUserModes() { + IrcUser *me_ = me(); + Q_ASSERT(me_); + + disconnect(me_, SIGNAL(userModesSet(QString)), this, SLOT(restoreUserModes())); + disconnect(me_, SIGNAL(userModesAdded(QString)), this, SLOT(restoreUserModes())); + + QString removeModes; + QString addModes = Core::userModes(userId(), networkId()); + QString currentModes = me_->userModes(); + + removeModes = currentModes; + removeModes.remove(QRegExp(QString("[%1]").arg(addModes))); + addModes.remove(QRegExp(QString("[%1]").arg(currentModes))); + + removeModes = QString("%1 -%2").arg(me_->nick(), removeModes); + addModes = QString("%1 +%2").arg(me_->nick(), addModes); + userInputHandler()->handleMode(BufferInfo(), removeModes); + userInputHandler()->handleMode(BufferInfo(), addModes); } void CoreNetwork::setUseAutoReconnect(bool use) { @@ -432,7 +517,12 @@ void CoreNetwork::doAutoReconnect() { } void CoreNetwork::sendPing() { - userInputHandler()->handlePing(BufferInfo(), QString()); + if(!gotPong()) { + disconnectFromIrc(false, QString("No Ping reply in %1 seconds.").arg(_pingTimer.interval() / 1000), true /* withReconnect */); + } else { + _gotPong = false; + userInputHandler()->handlePing(BufferInfo(), QString()); + } } void CoreNetwork::sendAutoWho() { @@ -464,18 +554,7 @@ void CoreNetwork::startAutoWhoCycle() { void CoreNetwork::sslErrors(const QList &sslErrors) { Q_UNUSED(sslErrors) socket.ignoreSslErrors(); - /* TODO errorhandling - QVariantMap errmsg; - QVariantList errnums; - foreach(QSslError err, errors) errnums << err.error(); - errmsg["SslErrors"] = errnums; - errmsg["SslCert"] = socket.peerCertificate().toPem(); - errmsg["PeerAddress"] = socket.peerAddress().toString(); - errmsg["PeerPort"] = socket.peerPort(); - errmsg["PeerName"] = socket.peerName(); - emit sslErrors(errmsg); - disconnectFromIrc(); - */ + // TODO errorhandling } #endif // HAVE_SSL @@ -495,6 +574,16 @@ void CoreNetwork::writeToSocket(const QByteArray &data) { _tokenBucket--; } +Network::Server CoreNetwork::usedServer() const { + if(_lastUsedServerIndex < serverList().count()) + return serverList()[_lastUsedServerIndex]; + + if(!serverList().isEmpty()) + return serverList()[0]; + + return Network::Server(); +} + void CoreNetwork::requestConnect() const { if(connectionState() != Disconnected) { qWarning() << "Requesting connect while already being connected!"; @@ -512,6 +601,18 @@ void CoreNetwork::requestDisconnect() const { } void CoreNetwork::requestSetNetworkInfo(const NetworkInfo &info) { + Network::Server currentServer = usedServer(); setNetworkInfo(info); Core::updateNetwork(coreSession()->user(), info); + + // the order of the servers might have changed, + // so we try to find the previously used server + _lastUsedServerIndex = 0; + for(int i = 0; i < serverList().count(); i++) { + Network::Server server = serverList()[i]; + if(server.host == currentServer.host && server.port == currentServer.port) { + _lastUsedServerIndex = i; + break; + } + } }