we use a nice queue and a 3 second delay (should later be made configurable). This
should prevent networks from throttling us.
For the enduser this primarily means that that annoying lag when sending to certain networks
such as Freenode should be history, at the cost of slightly slower away status updates.
if(conn) {
conn->userInput(bufinfo, msg);
} else {
- qWarning() << "Trying to send to unconnected network!";
+ qWarning() << "Trying to send to unconnected network:" << msg;
}
}
void IrcServerHandler::handleNick(const QString &prefix, const QList<QByteArray> ¶ms) {
IrcUser *ircuser = network()->updateNickFromMask(prefix);
- Q_ASSERT(ircuser);
+ if(!ircuser) {
+ qWarning() << "IrcServerHandler::handleNick(): Unknown IrcUser!";
+ return;
+ }
QString newnick = serverDecode(params[0]);
QString oldnick = ircuser->nick();
void IrcServerHandler::handlePart(const QString &prefix, const QList<QByteArray> ¶ms) {
IrcUser *ircuser = network()->updateNickFromMask(prefix);
QString channel = serverDecode(params[0]);
- Q_ASSERT(ircuser);
+ if(!ircuser) {
+ qWarning() << "IrcServerHandler::handlePart(): Unknown IrcUser!";
+ return;
+ }
ircuser->partChannel(channel);
void IrcServerHandler::handlePrivmsg(const QString &prefix, const QList<QByteArray> ¶ms) {
IrcUser *ircuser = network()->updateNickFromMask(prefix);
- Q_ASSERT(ircuser);
+ if(!ircuser) {
+ qWarning() << "IrcServerHandler::handlePrivmsg(): Unknown IrcUser!";
+ return;
+ }
if(params.isEmpty()) {
qWarning() << "IrcServerHandler::handlePrivmsg(): received PRIVMSG without target or message from:" << prefix;
/* RPL_ENDOFWHO: "<name> :End of WHO list" */
void IrcServerHandler::handle315(const QString &prefix, const QList<QByteArray> ¶ms) {
- Q_UNUSED(prefix)
- // FIXME temporarily made silent
- Q_UNUSED(params)
- // emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("[Who] %1").arg(serverDecode(params).join(" ")));
+ Q_UNUSED(prefix);
+ QStringList p = serverDecode(params);
+ if(p.count()) {
+ if(networkConnection()->setAutoWhoDone(p[0])) {
+ return; // stay silent
+ }
+ p.takeLast(); // should be "End of WHO list"
+ emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("[Who] End of /WHO list for %1").arg(p.join(" ")));
+ }
}
/* RPL_WHOISIDLE - "<nick> <integer> :seconds idle"
ircuser->setRealName(serverDecode(params.last()).section(" ", 1));
}
- // FIXME temporarily made silent
- //emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("[Who] %1").arg(serverDecode(params).join(" ")));
+ if(!networkConnection()->isAutoWhoInProgress(channel)) {
+ emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("[Who] %1").arg(serverDecode(params).join(" ")));
+ }
}
/* RPL_NAMREPLY */
_autoReconnectCount(0)
{
_autoReconnectTimer.setSingleShot(true);
- _previousConnectionAttemptFailed = false;
- _lastUsedServerlistIndex = 0;
- // TODO make configurable
- _whoTimer.setInterval(90 * 1000);
- _whoTimer.setSingleShot(false);
+
+ _previousConnectionAttemptFailed = false;
+ _lastUsedServerlistIndex = 0;
+
+ // TODO make autowho configurable (possibly per-network)
+ _autoWhoEnabled = true;
+ _autoWhoInterval = 90;
+ _autoWhoNickLimit = 0; // unlimited
+ _autoWhoDelay = 3;
+
+ _autoWhoTimer.setInterval(_autoWhoDelay * 1000);
+ _autoWhoTimer.setSingleShot(false);
+ _autoWhoCycleTimer.setInterval(_autoWhoInterval * 1000);
+ _autoWhoCycleTimer.setSingleShot(false);
QHash<QString, QString> channels = coreSession()->persistentChannels(networkId());
foreach(QString chan, channels.keys()) {
}
connect(&_autoReconnectTimer, SIGNAL(timeout()), this, SLOT(doAutoReconnect()));
- connect(&_whoTimer, SIGNAL(timeout()), this, SLOT(sendWho()));
+ connect(&_autoWhoTimer, SIGNAL(timeout()), this, SLOT(sendAutoWho()));
+ connect(&_autoWhoCycleTimer, SIGNAL(timeout()), this, SLOT(startAutoWhoCycle()));
connect(network, SIGNAL(currentServerSet(const QString &)), this, SLOT(networkInitialized(const QString &)));
connect(network, SIGNAL(useAutoReconnectSet(bool)), this, SLOT(autoReconnectSettingsChanged()));
delete _ctcpHandler;
}
-bool NetworkConnection::isConnected() const {
- // return socket.state() == QAbstractSocket::ConnectedState;
- return connectionState() == Network::Initialized;
-}
-
-Network::ConnectionState NetworkConnection::connectionState() const {
- return _connectionState;
-}
-
void NetworkConnection::setConnectionState(Network::ConnectionState state) {
_connectionState = state;
network()->setConnectionState(state);
emit connectionStateChanged(state);
}
-NetworkId NetworkConnection::networkId() const {
- return network()->networkId();
-}
-
-QString NetworkConnection::networkName() const {
- return network()->networkName();
-}
-
-Identity *NetworkConnection::identity() const {
- return coreSession()->identity(network()->identity());
-}
-
-Network *NetworkConnection::network() const {
- return _network;
-}
-
-CoreSession *NetworkConnection::coreSession() const {
- return _coreSession;
-}
-
-IrcServerHandler *NetworkConnection::ircServerHandler() const {
- return _ircServerHandler;
-}
-
-UserInputHandler *NetworkConnection::userInputHandler() const {
- return _userInputHandler;
-}
-
-CtcpHandler *NetworkConnection::ctcpHandler() const {
- return _ctcpHandler;
-}
-
QString NetworkConnection::serverDecode(const QByteArray &string) const {
return network()->decodeServerString(string);
}
setConnectionState(Network::Initialized);
network()->setConnected(true);
emit connected(networkId());
- if(!Global::SPUTDEV) {
- sendWho();
- _whoTimer.start();
+
+ if(_autoWhoEnabled) {
+ _autoWhoCycleTimer.start();
+ _autoWhoTimer.start();
+ startAutoWhoCycle(); // FIXME wait for autojoin to be completed
}
}
#ifndef QT_NO_OPENSSL
-void NetworkConnection::sslErrors(const QList<QSslError> &errors) {
+void NetworkConnection::sslErrors(const QList<QSslError> &sslErrors) {
socket.ignoreSslErrors();
/* TODO errorhandling
QVariantMap errmsg;
}
void NetworkConnection::socketDisconnected() {
- _whoTimer.stop();
+ _autoWhoCycleTimer.stop();
+ _autoWhoTimer.stop();
+ _autoWhoQueue.clear();
+ _autoWhoInProgress.clear();
+
network()->setConnected(false);
emit disconnected(networkId());
if(_autoReconnectCount != 0) {
putRawLine(msg);
}
-void NetworkConnection::sendWho() {
- foreach(QString chan, network()->channels()) {
+void NetworkConnection::sendAutoWho() {
+ while(!_autoWhoQueue.isEmpty()) {
+ QString chan = _autoWhoQueue.takeFirst();
+ IrcChannel *ircchan = network()->ircChannel(chan);
+ if(!ircchan) continue;
+ if(_autoWhoNickLimit > 0 && ircchan->ircUsers().count() > _autoWhoNickLimit) continue;
+ _autoWhoInProgress.insert(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 NetworkConnection::startAutoWhoCycle() {
+ if(!_autoWhoQueue.isEmpty()) {
+ _autoWhoCycleTimer.stop();
+ return;
}
+ _autoWhoQueue = network()->channels();
+}
+
+bool NetworkConnection::setAutoWhoDone(const QString &channel) {
+ return _autoWhoInProgress.remove(channel);
}
void NetworkConnection::setChannelJoined(const QString &channel) {
emit channelJoined(networkId(), channel, _channelKeys[channel.toLower()]);
+ _autoWhoQueue.prepend(channel); // prepend so this new chan is the first to be checked
}
void NetworkConnection::setChannelParted(const QString &channel) {
removeChannelKey(channel);
+ _autoWhoQueue.removeAll(channel);
+ _autoWhoInProgress.remove(channel);
emit channelParted(networkId(), channel);
}
# include <QTcpSocket>
#endif
+#include "coresession.h"
#include "identity.h"
#include "message.h"
#include "network.h"
#include "signalproxy.h"
-class CoreSession;
class Network;
class IrcServerHandler;
NetworkConnection(Network *network, CoreSession *session);
~NetworkConnection();
- NetworkId networkId() const;
- QString networkName() const;
- Network *network() const;
- Identity *identity() const;
- CoreSession *coreSession() const;
+ inline NetworkId networkId() const { return network()->networkId(); }
+ inline QString networkName() const { return network()->networkName(); }
+ inline Network *network() const { return _network; }
+ inline Identity *identity() const { return coreSession()->identity(network()->identity()); }
+ inline CoreSession *coreSession() const { return _coreSession; }
- bool isConnected() const;
- Network::ConnectionState connectionState() const;
+ inline bool isConnected() const { return connectionState() == Network::Initialized; }
+ inline Network::ConnectionState connectionState() const { return _connectionState; }
- IrcServerHandler *ircServerHandler() const;
- UserInputHandler *userInputHandler() const;
- CtcpHandler *ctcpHandler() const;
+ inline IrcServerHandler *ircServerHandler() const { return _ircServerHandler; }
+ inline UserInputHandler *userInputHandler() const { return _userInputHandler; }
+ inline CtcpHandler *ctcpHandler() const { return _ctcpHandler; }
//! Decode a string using the server (network) decoding.
QString serverDecode(const QByteArray &string) const;
inline QString channelKey(const QString &channel) const { return _channelKeys.value(channel.toLower(), QString()); }
inline QStringList persistentChannels() const { return _channelKeys.keys(); }
+ inline bool isAutoWhoInProgress(const QString &channel) const { return _autoWhoInProgress.contains(channel); }
+
public slots:
// void setServerOptions();
void connectToIrc(bool reconnecting = false);
void addChannelKey(const QString &channel, const QString &key);
void removeChannelKey(const QString &channel);
-private slots:
- void sendPerform();
- void autoReconnectSettingsChanged();
- void doAutoReconnect();
- void sendWho();
- void nickChanged(const QString &newNick, const QString &oldNick); // this signal is inteded to rename query buffers in the storage backend
+ bool setAutoWhoDone(const QString &channel);
signals:
// #void networkState(QString net, QVariantMap data);
void setConnectionState(Network::ConnectionState);
void networkInitialized(const QString ¤tServer);
+ void sendPerform();
+ void autoReconnectSettingsChanged();
+ void doAutoReconnect();
+ void sendAutoWho();
+ void startAutoWhoCycle();
+ void nickChanged(const QString &newNick, const QString &oldNick); // this signal is inteded to rename query buffers in the storage backend
+
#ifndef QT_NO_OPENSSL
void socketEncrypted();
void sslErrors(const QList<QSslError> &errors);
QTimer _autoReconnectTimer;
int _autoReconnectCount;
- QTimer _whoTimer;
-
bool _previousConnectionAttemptFailed;
int _lastUsedServerlistIndex;
+ bool _autoWhoEnabled;
+ QStringList _autoWhoQueue;
+ QSet<QString> _autoWhoInProgress;
+ int _autoWhoInterval;
+ int _autoWhoNickLimit;
+ int _autoWhoDelay;
+ QTimer _autoWhoTimer, _autoWhoCycleTimer;
+
+
class ParseError : public Exception {
public:
ParseError(QString cmd, QString prefix, QStringList params);
quasselVersion = "0.2.0-alpha5-pre";
quasselDate = "2008-04-08";
- quasselBuild = 711;
+ quasselBuild = 712;
//! Minimum client build number the core needs
clientBuildNeeded = 642;