#include "core.h"
#include "coresession.h"
#include "coreidentity.h"
+#include "corenetworkconfig.h"
#include "ircserverhandler.h"
-#include "userinputhandler.h"
+#include "coreuserinputhandler.h"
#include "ctcphandler.h"
+INIT_SYNCABLE_OBJECT(CoreNetwork)
CoreNetwork::CoreNetwork(const NetworkId &networkid, CoreSession *session)
: Network(networkid, session),
_coreSession(session),
_ircServerHandler(new IrcServerHandler(this)),
- _userInputHandler(new UserInputHandler(this)),
+ _userInputHandler(new CoreUserInputHandler(this)),
_ctcpHandler(new CtcpHandler(this)),
_autoReconnectCount(0),
_quitRequested(false),
_lastUsedServerIndex(0),
_lastPingTime(0),
- _maxPingCount(3),
- _pingCount(0),
-
- // TODO make autowho configurable (possibly per-network)
- _autoWhoEnabled(true),
- _autoWhoInterval(90),
- _autoWhoNickLimit(0), // unlimited
- _autoWhoDelay(5)
+ _pingCount(0)
+
{
_autoReconnectTimer.setSingleShot(true);
_socketCloseTimer.setSingleShot(true);
connect(&_socketCloseTimer, SIGNAL(timeout()), this, SLOT(socketCloseTimeout()));
- _pingTimer.setInterval(30000);
+ setPingInterval(networkConfig()->pingInterval());
connect(&_pingTimer, SIGNAL(timeout()), this, SLOT(sendPing()));
- _autoWhoTimer.setInterval(_autoWhoDelay * 1000);
- _autoWhoCycleTimer.setInterval(_autoWhoInterval * 1000);
+ setAutoWhoDelay(networkConfig()->autoWhoDelay());
+ setAutoWhoInterval(networkConfig()->autoWhoInterval());
QHash<QString, QString> channels = coreSession()->persistentChannels(networkId());
foreach(QString chan, channels.keys()) {
_channelKeys[chan.toLower()] = channels[chan];
}
+ connect(networkConfig(), SIGNAL(pingTimeoutEnabledSet(bool)), SLOT(enablePingTimeout(bool)));
+ connect(networkConfig(), SIGNAL(pingIntervalSet(int)), SLOT(setPingInterval(int)));
+ connect(networkConfig(), SIGNAL(autoWhoEnabledSet(bool)), SLOT(setAutoWhoEnabled(bool)));
+ connect(networkConfig(), SIGNAL(autoWhoIntervalSet(int)), SLOT(setAutoWhoInterval(int)));
+ connect(networkConfig(), SIGNAL(autoWhoDelaySet(int)), SLOT(setAutoWhoDelay(int)));
+
connect(&_autoReconnectTimer, SIGNAL(timeout()), this, SLOT(doAutoReconnect()));
connect(&_autoWhoTimer, SIGNAL(timeout()), this, SLOT(sendAutoWho()));
connect(&_autoWhoCycleTimer, SIGNAL(timeout()), this, SLOT(startAutoWhoCycle()));
connect(&_tokenBucketTimer, SIGNAL(timeout()), this, SLOT(fillBucketAndProcessQueue()));
- connect(this, SIGNAL(connectRequested()), this, SLOT(connectToIrc()));
-
connect(&socket, SIGNAL(connected()), this, SLOT(socketInitialized()));
connect(&socket, SIGNAL(disconnected()), this, SLOT(socketDisconnected()));
_autoReconnectCount = 0; // prohibiting auto reconnect
}
disablePingTimeout();
+ _msgQueue.clear();
IrcUser *me_ = me();
if(me_) {
}
// TokenBucket to avoid sending too much at once
- _messagesPerSecond = 1;
+ _messageDelay = 2200; // this seems to be a safe value (2.2 seconds delay)
_burstSize = 5;
- _tokenBucket = 5; // init with a full bucket
- _tokenBucketTimer.start(_messagesPerSecond * 1000);
+ _tokenBucket = _burstSize; // init with a full bucket
+ _tokenBucketTimer.start(_messageDelay);
+ if(networkInfo().useSasl) {
+ putRawLine(serverEncode(QString("CAP REQ :sasl")));
+ }
if(!server.password.isEmpty()) {
putRawLine(serverEncode(QString("PASS %1").arg(server.password)));
}
void CoreNetwork::socketDisconnected() {
disablePingTimeout();
+ _msgQueue.clear();
_autoWhoCycleTimer.stop();
_autoWhoTimer.stop();
setConnected(false);
emit disconnected(networkId());
if(_quitRequested) {
+ _quitRequested = false;
setConnectionState(Network::Disconnected);
Core::setNetworkConnected(userId(), networkId(), false);
} else if(_autoReconnectCount != 0) {
setConnectionState(Network::Reconnecting);
- if(_autoReconnectCount == autoReconnectRetries())
+ if(_autoReconnectCount == -1 || _autoReconnectCount == autoReconnectRetries())
doAutoReconnect(); // first try is immediate
else
_autoReconnectTimer.start();
if(useAutoReconnect()) {
// reset counter
- _autoReconnectCount = autoReconnectRetries();
+ _autoReconnectCount = unlimitedReconnectRetries() ? -1 : autoReconnectRetries();
}
// restore away state
enablePingTimeout();
- if(_autoWhoEnabled) {
+ if(networkConfig()->autoWhoEnabled()) {
_autoWhoCycleTimer.start();
_autoWhoTimer.start();
startAutoWhoCycle(); // FIXME wait for autojoin to be completed
qWarning() << "CoreNetwork::doAutoReconnect(): Cannot reconnect while not being disconnected!";
return;
}
- if(_autoReconnectCount > 0)
- _autoReconnectCount--;
+ if(_autoReconnectCount > 0 || _autoReconnectCount == -1)
+ _autoReconnectCount--; // -2 means we delay the next reconnect
connectToIrc(true);
}
qDebug() << "UserId:" << userId() << "Network:" << networkName() << "missed" << _pingCount << "pings."
<< "BA:" << socket.bytesAvailable() << "BTW:" << socket.bytesToWrite();
}
- if(_pingCount >= _maxPingCount && now - _lastPingTime <= (uint)(_pingTimer.interval() / 1000) + 1) {
+ if((int)_pingCount >= networkConfig()->maxPingCount() && now - _lastPingTime <= (uint)(_pingTimer.interval() / 1000) + 1) {
// the second check compares the actual elapsed time since the last ping and the pingTimer interval
// if the interval is shorter then the actual elapsed time it means that this thread was somehow blocked
// and unable to even handle a ping answer. So we ignore those misses.
- disconnectFromIrc(false, QString("No Ping reply in %1 seconds.").arg(_maxPingCount * _pingTimer.interval() / 1000), true /* withReconnect */);
+ disconnectFromIrc(false, QString("No Ping reply in %1 seconds.").arg(_pingCount * _pingTimer.interval() / 1000), true /* withReconnect */);
} else {
_lastPingTime = now;
_pingCount++;
}
}
-void CoreNetwork::enablePingTimeout() {
- resetPingTimeout();
- _pingTimer.start();
+void CoreNetwork::enablePingTimeout(bool enable) {
+ if(!enable)
+ disablePingTimeout();
+ else {
+ resetPingTimeout();
+ if(networkConfig()->pingTimeoutEnabled())
+ _pingTimer.start();
+ }
}
void CoreNetwork::disablePingTimeout() {
resetPingTimeout();
}
+void CoreNetwork::setPingInterval(int interval) {
+ _pingTimer.setInterval(interval * 1000);
+}
+
+/******** AutoWHO ********/
+
+void CoreNetwork::startAutoWhoCycle() {
+ if(!_autoWhoQueue.isEmpty()) {
+ _autoWhoCycleTimer.stop();
+ return;
+ }
+ _autoWhoQueue = channels();
+}
+
+void CoreNetwork::setAutoWhoDelay(int delay) {
+ _autoWhoTimer.setInterval(delay * 1000);
+}
+
+void CoreNetwork::setAutoWhoInterval(int interval) {
+ _autoWhoCycleTimer.setInterval(interval * 1000);
+}
+
+void CoreNetwork::setAutoWhoEnabled(bool enabled) {
+ if(enabled && isConnected() && !_autoWhoTimer.isActive())
+ _autoWhoTimer.start();
+ else if(!enabled) {
+ _autoWhoTimer.stop();
+ _autoWhoCycleTimer.stop();
+ }
+}
+
void CoreNetwork::sendAutoWho() {
// Don't send autowho if there are still some pending
if(_autoWhoPending.count())
QString chan = _autoWhoQueue.takeFirst();
IrcChannel *ircchan = ircChannel(chan);
if(!ircchan) continue;
- if(_autoWhoNickLimit > 0 && ircchan->ircUsers().count() > _autoWhoNickLimit) continue;
+ if(networkConfig()->autoWhoNickLimit() > 0 && ircchan->ircUsers().count() >= networkConfig()->autoWhoNickLimit())
+ continue;
_autoWhoPending[chan]++;
putRawLine("WHO " + serverEncode(chan));
- if(_autoWhoQueue.isEmpty() && _autoWhoEnabled && !_autoWhoCycleTimer.isActive()) {
- // Timer was stopped, means a new cycle is due immediately
- _autoWhoCycleTimer.start();
- startAutoWhoCycle();
- }
break;
}
-}
-
-void CoreNetwork::startAutoWhoCycle() {
- if(!_autoWhoQueue.isEmpty()) {
- _autoWhoCycleTimer.stop();
- return;
+ if(_autoWhoQueue.isEmpty() && networkConfig()->autoWhoEnabled() && !_autoWhoCycleTimer.isActive()) {
+ // Timer was stopped, means a new cycle is due immediately
+ _autoWhoCycleTimer.start();
+ startAutoWhoCycle();
}
- _autoWhoQueue = channels();
}
#ifdef HAVE_SSL
qWarning() << "Requesting connect while already being connected!";
return;
}
- Network::requestConnect();
+ QMetaObject::invokeMethod(const_cast<CoreNetwork *>(this), "connectToIrc", Qt::QueuedConnection);
}
void CoreNetwork::requestDisconnect() const {