This is a major internal change. Needs thorough testing.
disconnect(ircuser, 0, this, 0);
emit ircUserParted(ircuser);
- if(network->isMe(ircuser)) {
- // we left -> clean up the channel and destroy it
+ if(network->isMe(ircuser) || _userModes.isEmpty()) {
+ // in either case we're no longer in the channel
+ // -> clean up the channel and destroy it
QList<IrcUser *> users = _userModes.keys();
_userModes.clear();
foreach(IrcUser *user, users) {
if(!_channels.contains(channel)) {
_channels.insert(channel);
channel->joinIrcUsers(this);
- // connect(channel, SIGNAL(destroyed()), this, SLOT(channelDestroyed()));
}
}
QTextCodec *Network::_defaultCodecForServer = 0;
QTextCodec *Network::_defaultCodecForEncoding = 0;
QTextCodec *Network::_defaultCodecForDecoding = 0;
+
+Network::Server Network::Server::fromVariant(const QVariant &variant) {
+ QVariantMap serverMap = variant.toMap();
+ return Server(serverMap["Host"].toString(), serverMap["Port"].toUInt(), serverMap["Password"].toString(), serverMap["UseSSL"].toBool());
+}
+
+QVariant Network::Server::toVariant() const {
+ QVariantMap serverMap;
+ serverMap["Host"] = host;
+ serverMap["Port"] = port;
+ serverMap["Password"] = password;
+ serverMap["UseSSL"] = useSsl;
+ return QVariant::fromValue<QVariantMap>(serverMap);
+}
+
// ====================
// Public:
// ====================
info.codecForServer = codecForServer();
info.codecForEncoding = codecForEncoding();
info.codecForDecoding = codecForDecoding();
- info.serverList = serverList();
+ info.serverList = variantServerList();
info.useRandomServer = useRandomServer();
info.perform = perform();
info.useAutoIdentify = useAutoIdentify();
return nicks;
}
+QVariantList Network::variantServerList() const {
+ QVariantList servers;
+ ServerList::const_iterator serverIter = _serverList.constBegin();
+ while(serverIter != _serverList.constEnd()) {
+ servers << serverIter->toVariant();
+ serverIter++;
+ }
+ return servers;
+}
+
QString Network::prefixes() {
if(_prefixes.isNull())
determinePrefixes();
_ircUsers.clear();
QList<IrcChannel *> channels = ircChannels();
_ircChannels.clear();
-
+
foreach(IrcChannel *channel, channels) {
+ proxy()->detachObject(channel);
disconnect(channel, 0, this, 0);
}
foreach(IrcUser *user, users) {
+ proxy()->detachObject(user);
disconnect(user, 0, this, 0);
+ }
+
+ // the second loop is needed because quit can have sideffects
+ foreach(IrcUser *user, users) {
user->quit();
}
+
qDeleteAll(users);
qDeleteAll(channels);
}
}
void Network::setServerList(const QVariantList &serverList) {
- _serverList = serverList;
+ _serverList.clear();
+ foreach(QVariant variant, serverList) {
+ _serverList << Server::fromVariant(variant);
+ }
emit serverListSet(serverList);
}
newIrcChannel(channelIter.key(), channelIter.value().toMap());
channelIter++;
}
-
}
void Network::initSetSupports(const QVariantMap &supports) {
}
}
+void Network::initSetServerList(const QVariantList &serverList) {
+ foreach(QVariant variant, serverList) {
+ _serverList << Server::fromVariant(variant);
+ }
+}
+
IrcUser *Network::updateNickFromMask(const QString &mask) {
QString nick(nickFromMask(mask).toLower());
IrcUser *ircuser;
D_CHANMODE = 0x08
};
+ struct Server {
+ QString host;
+ uint port;
+ QString password;
+ bool useSsl;
+ Server() : port(0), useSsl(false) {}
+ Server(const QString &host, uint port, const QString &password, bool useSsl)
+ : host(host), port(port), password(password), useSsl(useSsl) {}
+
+ static Server fromVariant(const QVariant &variant);
+ QVariant toVariant() const;
+ };
+ typedef QList<Server> ServerList;
Network(const NetworkId &networkid, QObject *parent = 0);
~Network();
inline IdentityId identity() const { return _identity; }
QStringList nicks() const;
inline QStringList channels() const { return _ircChannels.keys(); }
- inline const QVariantList &serverList() const { return _serverList; }
+ inline const ServerList &serverList() const { return _serverList; }
+ QVariantList variantServerList() const;
inline bool useRandomServer() const { return _useRandomServer; }
inline const QStringList &perform() const { return _perform; }
inline bool useAutoIdentify() const { return _useAutoIdentify; }
static void setDefaultCodecForEncoding(const QByteArray &name);
static void setDefaultCodecForDecoding(const QByteArray &name);
- bool autoAwayActive() const { return _autoAwayActive; }
- void setAutoAwayActive(bool active) { _autoAwayActive = active; }
+ inline bool autoAwayActive() const { return _autoAwayActive; }
+ inline void setAutoAwayActive(bool active) { _autoAwayActive = active; }
public slots:
void setNetworkName(const QString &networkName);
void setCurrentServer(const QString ¤tServer);
void setConnected(bool isConnected);
- //void setConnectionState(Network::ConnectionState state);
void setConnectionState(int state);
- void setMyNick(const QString &mynick);
+ virtual void setMyNick(const QString &mynick);
void setLatency(int latency);
void setIdentity(IdentityId);
void setUseAutoIdentify(bool);
void setAutoIdentifyService(const QString &);
void setAutoIdentifyPassword(const QString &);
- void setUseAutoReconnect(bool);
- void setAutoReconnectInterval(quint32);
- void setAutoReconnectRetries(quint16);
+ virtual void setUseAutoReconnect(bool);
+ virtual void setAutoReconnectInterval(quint32);
+ virtual void setAutoReconnectRetries(quint16);
void setUnlimitedReconnectRetries(bool);
void setRejoinChannels(bool);
//init geters
QVariantMap initSupports() const;
- inline QVariantList initServerList() const { return serverList(); }
+ inline QVariantList initServerList() const { return variantServerList(); }
virtual QVariantMap initIrcUsersAndChannels() const;
-// QStringList initIrcUsers() const;
-// QStringList initIrcChannels() const;
//init seters
void initSetSupports(const QVariantMap &supports);
- inline void initSetServerList(const QVariantList &serverList) { setServerList(serverList); }
+ void initSetServerList(const QVariantList &serverList);
virtual void initSetIrcUsersAndChannels(const QVariantMap &usersAndChannels);
-// void initSetIrcUsers(const QStringList &hostmasks);
-// void initSetIrcChannels(const QStringList &channels);
IrcUser *updateNickFromMask(const QString &mask);
void ircChannelAdded(const QString &channelname);
void ircChannelAdded(IrcChannel *);
- void connectRequested(NetworkId id = 0) const;
- void disconnectRequested(NetworkId id = 0) const;
+ void connectRequested() const;
+ void disconnectRequested() const;
void setNetworkInfoRequested(const NetworkInfo &) const;
protected:
QHash<QString, IrcChannel *> _ircChannels; // stores all known channels
QHash<QString, QString> _supports; // stores results from RPL_ISUPPORT
- QVariantList _serverList;
+ ServerList _serverList;
bool _useRandomServer;
QStringList _perform;
const QList<int> &SignalProxy::argTypes(QObject *obj, int methodId) {
const QMetaObject *meta = metaObject(obj);
- if(!_classInfo.contains(meta))
- qDebug() << obj << meta;
Q_ASSERT(_classInfo.contains(meta));
if(!_classInfo[meta]->argTypes.contains(methodId))
setArgTypes(obj, methodId);
}
void SignalProxy::detachObject(QObject* obj) {
+ stopSync(static_cast<SyncableObject *>(obj));
detachSignals(obj);
detachSlots(obj);
- stopSync(static_cast<SyncableObject *>(obj));
}
void SignalProxy::detachSignals(QObject* sender) {
coreusersettings.cpp
ctcphandler.cpp
ircserverhandler.cpp
- networkconnection.cpp
sessionthread.cpp
sqlitestorage.cpp
storage.cpp
coresession.h
ctcphandler.h
ircserverhandler.h
- networkconnection.h
sqlitestorage.h
storage.h
sessionthread.h
#include "util.h"
#include "logger.h"
-BasicHandler::BasicHandler(NetworkConnection *parent)
+BasicHandler::BasicHandler(CoreNetwork *parent)
: QObject(parent),
defaultHandler(-1),
- _networkConnection(parent),
+ _network(parent),
initDone(false)
{
connect(this, SIGNAL(displayMsg(Message::Type, BufferInfo::Type, QString, QString, QString, Message::Flags)),
- networkConnection(), SIGNAL(displayMsg(Message::Type, BufferInfo::Type, QString, QString, QString, Message::Flags)));
+ network(), SIGNAL(displayMsg(Message::Type, BufferInfo::Type, QString, QString, QString, Message::Flags)));
connect(this, SIGNAL(putCmd(QString, const QList<QByteArray> &, const QByteArray &)),
- networkConnection(), SLOT(putCmd(QString, const QList<QByteArray> &, const QByteArray &)));
+ network(), SLOT(putCmd(QString, const QList<QByteArray> &, const QByteArray &)));
connect(this, SIGNAL(putRawLine(const QByteArray &)),
- networkConnection(), SLOT(putRawLine(const QByteArray &)));
+ network(), SLOT(putRawLine(const QByteArray &)));
}
QStringList BasicHandler::providesHandlers() {
}
QString BasicHandler::serverDecode(const QByteArray &string) {
- return networkConnection()->serverDecode(string);
+ return network()->serverDecode(string);
}
QStringList BasicHandler::serverDecode(const QList<QByteArray> &stringlist) {
QStringList list;
- foreach(QByteArray s, stringlist) list << networkConnection()->serverDecode(s);
+ foreach(QByteArray s, stringlist) list << network()->serverDecode(s);
return list;
}
QString BasicHandler::channelDecode(const QString &bufferName, const QByteArray &string) {
- return networkConnection()->channelDecode(bufferName, string);
+ return network()->channelDecode(bufferName, string);
}
QStringList BasicHandler::channelDecode(const QString &bufferName, const QList<QByteArray> &stringlist) {
QStringList list;
- foreach(QByteArray s, stringlist) list << networkConnection()->channelDecode(bufferName, s);
+ foreach(QByteArray s, stringlist) list << network()->channelDecode(bufferName, s);
return list;
}
QString BasicHandler::userDecode(const QString &userNick, const QByteArray &string) {
- return networkConnection()->userDecode(userNick, string);
+ return network()->userDecode(userNick, string);
}
QStringList BasicHandler::userDecode(const QString &userNick, const QList<QByteArray> &stringlist) {
QStringList list;
- foreach(QByteArray s, stringlist) list << networkConnection()->userDecode(userNick, s);
+ foreach(QByteArray s, stringlist) list << network()->userDecode(userNick, s);
return list;
}
/*** ***/
QByteArray BasicHandler::serverEncode(const QString &string) {
- return networkConnection()->serverEncode(string);
+ return network()->serverEncode(string);
}
QList<QByteArray> BasicHandler::serverEncode(const QStringList &stringlist) {
QList<QByteArray> list;
- foreach(QString s, stringlist) list << networkConnection()->serverEncode(s);
+ foreach(QString s, stringlist) list << network()->serverEncode(s);
return list;
}
QByteArray BasicHandler::channelEncode(const QString &bufferName, const QString &string) {
- return networkConnection()->channelEncode(bufferName, string);
+ return network()->channelEncode(bufferName, string);
}
QList<QByteArray> BasicHandler::channelEncode(const QString &bufferName, const QStringList &stringlist) {
QList<QByteArray> list;
- foreach(QString s, stringlist) list << networkConnection()->channelEncode(bufferName, s);
+ foreach(QString s, stringlist) list << network()->channelEncode(bufferName, s);
return list;
}
QByteArray BasicHandler::userEncode(const QString &userNick, const QString &string) {
- return networkConnection()->userEncode(userNick, string);
+ return network()->userEncode(userNick, string);
}
QList<QByteArray> BasicHandler::userEncode(const QString &userNick, const QStringList &stringlist) {
QList<QByteArray> list;
- foreach(QString s, stringlist) list << networkConnection()->userEncode(userNick, s);
+ foreach(QString s, stringlist) list << network()->userEncode(userNick, s);
return list;
}
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
-#ifndef _BASICHANDLER_H_
-#define _BASICHANDLER_H_
+#ifndef BASICHANDLER_H_
+#define BASICHANDLER_H_
#include <QObject>
#include <QString>
#include "message.h"
-#include "networkconnection.h"
+#include "corenetwork.h"
class CoreSession;
Q_OBJECT
public:
- BasicHandler(NetworkConnection *parent = 0);
+ BasicHandler(CoreNetwork *parent = 0);
QStringList providesHandlers();
QGenericArgument val7 = QGenericArgument(), QGenericArgument val8 = QGenericArgument());
- inline Network *network() const { return _networkConnection->network(); }
- inline NetworkConnection *networkConnection() const { return _networkConnection; }
- inline CoreSession *coreSession() const { return _networkConnection->coreSession(); }
+ inline CoreNetwork *network() const { return _network; }
+ inline CoreSession *coreSession() const { return _network->coreSession(); }
BufferInfo::Type typeByTarget(const QString &target) const;
const QHash<QString, int> &handlerHash();
QHash<QString, int> _handlerHash;
int defaultHandler;
- NetworkConnection *_networkConnection;
+ CoreNetwork *_network;
bool initDone;
};
#endif
#include "coreirclisthelper.h"
-#include "networkconnection.h"
+#include "corenetwork.h"
#include "userinputhandler.h"
QVariantList CoreIrcListHelper::requestChannelList(const NetworkId &netId, const QStringList &channelFilters) {
}
bool CoreIrcListHelper::dispatchQuery(const NetworkId &netId, const QString &query) {
- NetworkConnection *networkConnection = coreSession()->networkConnection(netId);
- if(networkConnection) {
+ CoreNetwork *network = coreSession()->network(netId);
+ if(network) {
_channelLists[netId] = QList<ChannelDescription>();
- networkConnection->userInputHandler()->handleList(BufferInfo(), query);
+ network->userInputHandler()->handleList(BufferInfo(), query);
_queryTimeout[startTimer(10000)] = netId;
return true;
} else {
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
-#include "core.h"
#include "corenetwork.h"
+
+
+#include "core.h"
#include "coresession.h"
+#include "identity.h"
-#include "logger.h"
+#include "ircserverhandler.h"
+#include "userinputhandler.h"
+#include "ctcphandler.h"
CoreNetwork::CoreNetwork(const NetworkId &networkid, CoreSession *session)
: Network(networkid, session),
- _coreSession(session)
+ _coreSession(session),
+ _ircServerHandler(new IrcServerHandler(this)),
+ _userInputHandler(new UserInputHandler(this)),
+ _ctcpHandler(new CtcpHandler(this)),
+ _autoReconnectCount(0),
+ _quitRequested(false),
+
+ _previousConnectionAttemptFailed(false),
+ _lastUsedServerIndex(0),
+
+ // TODO make autowho configurable (possibly per-network)
+ _autoWhoEnabled(true),
+ _autoWhoInterval(90),
+ _autoWhoNickLimit(0), // unlimited
+ _autoWhoDelay(3)
{
+ _autoReconnectTimer.setSingleShot(true);
+ _socketCloseTimer.setSingleShot(true);
+ connect(&_socketCloseTimer, SIGNAL(timeout()), this, SLOT(socketCloseTimeout()));
+
+ _pingTimer.setInterval(60000);
+ connect(&_pingTimer, SIGNAL(timeout()), this, SLOT(sendPing()));
+
+ _autoWhoTimer.setInterval(_autoWhoDelay * 1000);
+ _autoWhoCycleTimer.setInterval(_autoWhoInterval * 1000);
+
+ QHash<QString, QString> channels = coreSession()->persistentChannels(networkId());
+ foreach(QString chan, channels.keys()) {
+ _channelKeys[chan.toLower()] = channels[chan];
+ }
+
+ 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(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<QSslError> &)), this, SLOT(sslErrors(const QList<QSslError> &)));
+#else
+ connect(&socket, SIGNAL(connected()), this, SLOT(socketInitialized()));
+#endif
+}
+
+CoreNetwork::~CoreNetwork() {
+ if(connectionState() != Disconnected && connectionState() != Network::Reconnecting)
+ disconnectFromIrc(false); // clean up, but this does not count as requested disconnect!
+ disconnect(&socket, 0, this, 0); // this keeps the socket from triggering events during clean up
+ delete _ircServerHandler;
+ delete _userInputHandler;
+ delete _ctcpHandler;
+}
+
+QString CoreNetwork::channelDecode(const QString &bufferName, const QByteArray &string) const {
+ if(!bufferName.isEmpty()) {
+ IrcChannel *channel = ircChannel(bufferName);
+ if(channel)
+ return channel->decodeString(string);
+ }
+ return decodeString(string);
+}
+
+QString CoreNetwork::userDecode(const QString &userNick, const QByteArray &string) const {
+ IrcUser *user = ircUser(userNick);
+ if(user)
+ return user->decodeString(string);
+ return decodeString(string);
+}
+
+QByteArray CoreNetwork::channelEncode(const QString &bufferName, const QString &string) const {
+ if(!bufferName.isEmpty()) {
+ IrcChannel *channel = ircChannel(bufferName);
+ if(channel)
+ return channel->encodeString(string);
+ }
+ return encodeString(string);
+}
+
+QByteArray CoreNetwork::userEncode(const QString &userNick, const QString &string) const {
+ IrcUser *user = ircUser(userNick);
+ if(user)
+ return user->encodeString(string);
+ return encodeString(string);
+}
+
+void CoreNetwork::connectToIrc(bool reconnecting) {
+ if(!reconnecting && useAutoReconnect() && _autoReconnectCount == 0) {
+ _autoReconnectTimer.setInterval(autoReconnectInterval() * 1000);
+ if(unlimitedReconnectRetries())
+ _autoReconnectCount = -1;
+ else
+ _autoReconnectCount = autoReconnectRetries();
+ }
+ if(serverList().isEmpty()) {
+ qWarning() << "Server list empty, ignoring connect request!";
+ return;
+ }
+ Identity *identity = identityPtr();
+ if(!identity) {
+ qWarning() << "Invalid identity configures, ignoring connect request!";
+ return;
+ }
+ // 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()) {
+ _lastUsedServerIndex = 0;
+ }
+ }
+ _previousConnectionAttemptFailed = false;
+
+ 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));
+ socket.connectToHost(server.host, server.port);
+}
+
+void CoreNetwork::disconnectFromIrc(bool requested, const QString &reason) {
+ _quitRequested = requested; // see socketDisconnected();
+ _autoReconnectTimer.stop();
+ _autoReconnectCount = 0; // prohibiting auto reconnect
+ 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();
+ 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);
+ }
+}
+
+void CoreNetwork::userInput(BufferInfo buf, QString msg) {
+ userInputHandler()->handleUserInput(buf, msg);
+}
+
+void CoreNetwork::putRawLine(QByteArray s) {
+ if(_tokenBucket > 0)
+ writeToSocket(s);
+ else
+ _msgQueue.append(s);
+}
+
+void CoreNetwork::putCmd(const QString &cmd, const QList<QByteArray> ¶ms, const QByteArray &prefix) {
+ QByteArray msg;
+
+ if(!prefix.isEmpty())
+ msg += ":" + prefix + " ";
+ msg += cmd.toUpper().toAscii();
+
+ for(int i = 0; i < params.size() - 1; i++) {
+ msg += " " + params[i];
+ }
+ if(!params.isEmpty())
+ msg += " :" + params.last();
+
+ putRawLine(msg);
+}
+
+void CoreNetwork::setChannelJoined(const QString &channel) {
+ _autoWhoQueue.prepend(channel.toLower()); // prepend so this new chan is the first to be checked
+
+ Core::setChannelPersistent(userId(), networkId(), channel, true);
+ Core::setPersistentChannelKey(userId(), networkId(), channel, _channelKeys[channel.toLower()]);
+}
+
+void CoreNetwork::setChannelParted(const QString &channel) {
+ removeChannelKey(channel);
+ _autoWhoQueue.removeAll(channel.toLower());
+ _autoWhoInProgress.remove(channel.toLower());
+
+ Core::setChannelPersistent(userId(), networkId(), channel, false);
+}
+
+void CoreNetwork::addChannelKey(const QString &channel, const QString &key) {
+ if(key.isEmpty()) {
+ removeChannelKey(channel);
+ } else {
+ _channelKeys[channel.toLower()] = key;
+ }
+}
+
+void CoreNetwork::removeChannelKey(const QString &channel) {
+ _channelKeys.remove(channel.toLower());
+}
+
+bool CoreNetwork::setAutoWhoDone(const QString &channel) {
+ if(_autoWhoInProgress.value(channel.toLower(), 0) <= 0)
+ return false;
+ _autoWhoInProgress[channel.toLower()]--;
+ return true;
+}
+
+void CoreNetwork::setMyNick(const QString &mynick) {
+ Network::setMyNick(mynick);
+ if(connectionState() == Network::Initializing)
+ networkInitialized();
+}
+
+void CoreNetwork::socketHasData() {
+ while(socket.canReadLine()) {
+ QByteArray s = socket.readLine().trimmed();
+ ircServerHandler()->handleServerMsg(s);
+ }
+}
+
+void CoreNetwork::socketError(QAbstractSocket::SocketError) {
+ _previousConnectionAttemptFailed = true;
+ qWarning() << qPrintable(tr("Could not connect to %1 (%2)").arg(networkName(), socket.errorString()));
+ emit connectionError(socket.errorString());
+ emit displayMsg(Message::Error, BufferInfo::StatusBuffer, "", tr("Connection failure: %1").arg(socket.errorString()));
+ emitConnectionError(socket.errorString());
+ if(socket.state() < QAbstractSocket::ConnectedState) {
+ socketDisconnected();
+ }
+}
+
+#ifdef HAVE_SSL
+void CoreNetwork::sslSocketConnected() {
+ if(!usedServer().useSsl)
+ socketInitialized();
+ else
+ socket.startClientEncryption();
+}
+#endif
+
+void CoreNetwork::socketInitialized() {
+ Identity *identity = identityPtr();
+ if(!identity) {
+ qCritical() << "Identity invalid!";
+ disconnectFromIrc();
+ return;
+ }
+
+ // TokenBucket to avoid sending too much at once
+ _messagesPerSecond = 1;
+ _burstSize = 5;
+ _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)));
+ }
+ putRawLine(serverEncode(QString("NICK :%1").arg(identity->nicks()[0])));
+ putRawLine(serverEncode(QString("USER %1 8 * :%2").arg(identity->ident(), identity->realName())));
+}
+
+void CoreNetwork::socketDisconnected() {
+ _pingTimer.stop();
+ _autoWhoCycleTimer.stop();
+ _autoWhoTimer.stop();
+ _autoWhoQueue.clear();
+ _autoWhoInProgress.clear();
+
+ _socketCloseTimer.stop();
+
+ _tokenBucketTimer.stop();
+
+ IrcUser *me_ = me();
+ if(me_) {
+ foreach(QString channel, me_->channels())
+ emit displayMsg(Message::Quit, BufferInfo::ChannelBuffer, channel, "", me_->hostmask());
+ }
+
+ setConnected(false);
+ emit disconnected(networkId());
+ if(_quitRequested) {
+ setConnectionState(Network::Disconnected);
+ Core::setNetworkConnected(userId(), networkId(), false);
+ } else if(_autoReconnectCount != 0) {
+ setConnectionState(Network::Reconnecting);
+ if(_autoReconnectCount == autoReconnectRetries())
+ doAutoReconnect(); // first try is immediate
+ else
+ _autoReconnectTimer.start();
+ }
+}
+
+void CoreNetwork::socketStateChanged(QAbstractSocket::SocketState socketState) {
+ Network::ConnectionState state;
+ switch(socketState) {
+ case QAbstractSocket::UnconnectedState:
+ state = Network::Disconnected;
+ break;
+ case QAbstractSocket::HostLookupState:
+ case QAbstractSocket::ConnectingState:
+ state = Network::Connecting;
+ break;
+ case QAbstractSocket::ConnectedState:
+ state = Network::Initializing;
+ break;
+ case QAbstractSocket::ClosingState:
+ state = Network::Disconnecting;
+ break;
+ default:
+ state = Network::Disconnected;
+ }
+ setConnectionState(state);
+}
+
+void CoreNetwork::networkInitialized() {
+ setConnectionState(Network::Initialized);
+ setConnected(true);
+
+ if(useAutoReconnect()) {
+ // reset counter
+ _autoReconnectCount = autoReconnectRetries();
+ }
+
+ sendPerform();
+
+ _pingTimer.start();
+
+ if(_autoWhoEnabled) {
+ _autoWhoCycleTimer.start();
+ _autoWhoTimer.start();
+ startAutoWhoCycle(); // FIXME wait for autojoin to be completed
+ }
+
+ Core::bufferInfo(userId(), networkId(), BufferInfo::StatusBuffer); // create status buffer
+ Core::setNetworkConnected(userId(), networkId(), true);
+}
+
+void CoreNetwork::sendPerform() {
+ BufferInfo statusBuf = BufferInfo::fakeStatusBuffer(networkId());
+
+ // do auto identify
+ if(useAutoIdentify() && !autoIdentifyService().isEmpty() && !autoIdentifyPassword().isEmpty()) {
+ userInputHandler()->handleMsg(statusBuf, QString("%1 IDENTIFY %2").arg(autoIdentifyService(), autoIdentifyPassword()));
+ }
+
+ // send perform list
+ foreach(QString line, perform()) {
+ if(!line.isEmpty()) userInput(statusBuf, line);
+ }
+
+ // 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);
+ }
+ }
+ QString joinString = QString("%1 %2").arg(channels.join(",")).arg(keys.join(",")).trimmed();
+ if(!joinString.isEmpty())
+ userInputHandler()->handleJoin(statusBuf, joinString);
+}
+
+void CoreNetwork::setUseAutoReconnect(bool use) {
+ Network::setUseAutoReconnect(use);
+ if(!use)
+ _autoReconnectTimer.stop();
+}
+
+void CoreNetwork::setAutoReconnectInterval(quint32 interval) {
+ Network::setAutoReconnectInterval(interval);
+ _autoReconnectTimer.setInterval(interval * 1000);
+}
+
+void CoreNetwork::setAutoReconnectRetries(quint16 retries) {
+ Network::setAutoReconnectRetries(retries);
+ if(_autoReconnectCount != 0) {
+ if(unlimitedReconnectRetries())
+ _autoReconnectCount = -1;
+ else
+ _autoReconnectCount = autoReconnectRetries();
+ }
+}
+
+void CoreNetwork::doAutoReconnect() {
+ if(connectionState() != Network::Disconnected && connectionState() != Network::Reconnecting) {
+ qWarning() << "CoreNetwork::doAutoReconnect(): Cannot reconnect while not being disconnected!";
+ return;
+ }
+ if(_autoReconnectCount > 0)
+ _autoReconnectCount--;
+ connectToIrc(true);
+}
+
+void CoreNetwork::sendPing() {
+ userInputHandler()->handlePing(BufferInfo(), QString());
+}
+
+void CoreNetwork::sendAutoWho() {
+ while(!_autoWhoQueue.isEmpty()) {
+ QString chan = _autoWhoQueue.takeFirst();
+ IrcChannel *ircchan = ircChannel(chan);
+ if(!ircchan) continue;
+ if(_autoWhoNickLimit > 0 && ircchan->ircUsers().count() > _autoWhoNickLimit) continue;
+ _autoWhoInProgress[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;
+ }
+ _autoWhoQueue = channels();
+}
+
+#ifdef HAVE_SSL
+void CoreNetwork::sslErrors(const QList<QSslError> &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();
+ */
+}
+#endif // HAVE_SSL
+
+void CoreNetwork::fillBucketAndProcessQueue() {
+ if(_tokenBucket < _burstSize) {
+ _tokenBucket++;
+ }
+
+ while(_msgQueue.size() > 0 && _tokenBucket > 0) {
+ writeToSocket(_msgQueue.takeFirst());
+ }
+}
+
+void CoreNetwork::writeToSocket(const QByteArray &data) {
+ socket.write(data);
+ socket.write("\r\n");
+ _tokenBucket--;
}
void CoreNetwork::requestConnect() const {
qWarning() << "Requesting connect while already being connected!";
return;
}
- emit connectRequested(networkId());
+ Network::requestConnect();
}
void CoreNetwork::requestDisconnect() const {
qWarning() << "Requesting disconnect while not being connected!";
return;
}
- emit disconnectRequested(networkId());
+ userInputHandler()->handleQuit(BufferInfo(), QString());
}
void CoreNetwork::requestSetNetworkInfo(const NetworkInfo &info) {
#include "network.h"
#include "coreircchannel.h"
-class CoreSession;
+#include <QTimer>
+
+#ifdef HAVE_SSL
+# include <QSslSocket>
+# include <QSslError>
+#else
+# include <QTcpSocket>
+#endif
+
+#include "coresession.h"
+
+class Identity;
+class IrcServerHandler;
+class UserInputHandler;
+class CtcpHandler;
class CoreNetwork : public Network {
Q_OBJECT
public:
CoreNetwork(const NetworkId &networkid, CoreSession *session);
-
+ ~CoreNetwork();
inline virtual const QMetaObject *syncMetaObject() const { return &Network::staticMetaObject; }
+ inline Identity *identityPtr() const { return coreSession()->identity(identity()); }
inline CoreSession *coreSession() const { return _coreSession; }
+ 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.
+ inline QString serverDecode(const QByteArray &string) const { return decodeServerString(string); }
+
+ //! Decode a string using a channel-specific encoding if one is set (and use the standard encoding else).
+ QString channelDecode(const QString &channelName, const QByteArray &string) const;
+
+ //! Decode a string using an IrcUser-specific encoding, if one exists (using the standaed encoding else).
+ QString userDecode(const QString &userNick, const QByteArray &string) const;
+
+ //! Encode a string using the server (network) encoding.
+ inline QByteArray serverEncode(const QString &string) const { return encodeServerString(string); }
+
+ //! Encode a string using the channel-specific encoding, if set, and use the standard encoding else.
+ QByteArray channelEncode(const QString &channelName, const QString &string) const;
+
+ //! Encode a string using the user-specific encoding, if set, and use the standard encoding else.
+ QByteArray userEncode(const QString &userNick, const QString &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.value(channel.toLower(), 0); }
+
+ inline UserId userId() const { return _coreSession->user(); }
+
public slots:
+ virtual void setMyNick(const QString &mynick);
+
virtual void requestConnect() const;
virtual void requestDisconnect() const;
virtual void requestSetNetworkInfo(const NetworkInfo &info);
+ virtual void setUseAutoReconnect(bool);
+ virtual void setAutoReconnectInterval(quint32);
+ virtual void setAutoReconnectRetries(quint16);
+
+ void connectToIrc(bool reconnecting = false);
+ void disconnectFromIrc(bool requested = true, const QString &reason = QString());
+
+ void userInput(BufferInfo bufferInfo, QString msg);
+ void putRawLine(QByteArray input);
+ void putCmd(const QString &cmd, const QList<QByteArray> ¶ms, const QByteArray &prefix = QByteArray());
+
+ void setChannelJoined(const QString &channel);
+ void setChannelParted(const QString &channel);
+ void addChannelKey(const QString &channel, const QString &key);
+ void removeChannelKey(const QString &channel);
+
+ bool setAutoWhoDone(const QString &channel);
+
+ inline const Server &usedServer() const { return serverList()[_lastUsedServerIndex]; }
+
+signals:
+ void recvRawServerMsg(QString);
+ void displayStatusMsg(QString);
+ void displayMsg(Message::Type, BufferInfo::Type, QString target, QString text, QString sender = "", Message::Flags flags = Message::None);
+ void disconnected(NetworkId networkId);
+ void connectionError(const QString &errorMsg);
+
+ void quitRequested(NetworkId networkId);
+ void sslErrors(const QVariant &errorData);
+
protected:
inline virtual IrcChannel *ircChannelFactory(const QString &channelname) { return new CoreIrcChannel(channelname, this); }
+private slots:
+ void socketHasData();
+ void socketError(QAbstractSocket::SocketError);
+ void socketInitialized();
+ inline void socketCloseTimeout() { socket.disconnectFromHost(); }
+ void socketDisconnected();
+ void socketStateChanged(QAbstractSocket::SocketState);
+ void networkInitialized();
+
+ void sendPerform();
+ void doAutoReconnect();
+ void sendPing();
+ void sendAutoWho();
+ void startAutoWhoCycle();
+
+#ifdef HAVE_SSL
+ void sslSocketConnected();
+ void sslErrors(const QList<QSslError> &errors);
+#endif
+
+ void fillBucketAndProcessQueue();
+
+ void writeToSocket(const QByteArray &data);
+
private:
CoreSession *_coreSession;
+
+#ifdef HAVE_SSL
+ QSslSocket socket;
+#else
+ QTcpSocket socket;
+#endif
+
+ IrcServerHandler *_ircServerHandler;
+ UserInputHandler *_userInputHandler;
+ CtcpHandler *_ctcpHandler;
+
+ QHash<QString, QString> _channelKeys; // stores persistent channels and their passwords, if any
+
+ QTimer _autoReconnectTimer;
+ int _autoReconnectCount;
+
+ QTimer _socketCloseTimer;
+
+ /* this flag triggers quitRequested() once the socket is closed
+ * it is needed to determine whether or not the connection needs to be
+ * in the automatic session restore. */
+ bool _quitRequested;
+
+ bool _previousConnectionAttemptFailed;
+ int _lastUsedServerIndex;
+
+ QTimer _pingTimer;
+
+ bool _autoWhoEnabled;
+ QStringList _autoWhoQueue;
+ QHash<QString, int> _autoWhoInProgress;
+ int _autoWhoInterval;
+ int _autoWhoNickLimit;
+ int _autoWhoDelay;
+ QTimer _autoWhoTimer, _autoWhoCycleTimer;
+
+ QTimer _tokenBucketTimer;
+ int _messagesPerSecond; // token refill speed
+ int _burstSize; // size of the token bucket
+ int _tokenBucket; // the virtual bucket that holds the tokens
+ QList<QByteArray> _msgQueue;
};
#endif //CORENETWORK_H
#include "core.h"
#include "coresession.h"
-#include "networkconnection.h"
#include "userinputhandler.h"
-
#include "signalproxy.h"
#include "buffersyncer.h"
#include "corebacklogmanager.h"
connect(p, SIGNAL(connected()), this, SLOT(clientsConnected()));
connect(p, SIGNAL(disconnected()), this, SLOT(clientsDisconnected()));
- //p->attachSlot(SIGNAL(disconnectFromNetwork(NetworkId)), this, SLOT(disconnectFromNetwork(NetworkId))); // FIXME
p->attachSlot(SIGNAL(sendInput(BufferInfo, QString)), this, SLOT(msgFromClient(BufferInfo, QString)));
p->attachSignal(this, SIGNAL(displayMsg(Message)));
p->attachSignal(this, SIGNAL(displayStatusMsg(QString, QString)));
- p->attachSignal(this, SIGNAL(bufferInfoUpdated(BufferInfo)));
p->attachSignal(this, SIGNAL(identityCreated(const Identity &)));
p->attachSignal(this, SIGNAL(identityRemoved(IdentityId)));
CoreSession::~CoreSession() {
saveSessionState();
- foreach(NetworkConnection *conn, _connections.values()) {
- delete conn;
- }
foreach(CoreNetwork *net, _networks.values()) {
delete net;
}
return 0;
}
-NetworkConnection *CoreSession::networkConnection(NetworkId id) const {
- if(_connections.contains(id)) return _connections[id];
- return 0;
-}
-
Identity *CoreSession::identity(IdentityId id) const {
if(_identities.contains(id)) return _identities[id];
return 0;
}
void CoreSession::saveSessionState() const {
-
}
void CoreSession::restoreSessionState() {
QList<NetworkId> nets = Core::connectedNetworks(user());
+ CoreNetwork *net = 0;
foreach(NetworkId id, nets) {
- connectToNetwork(id);
+ net = network(id);
+ Q_ASSERT(net);
+ net->connectToIrc();
}
}
-void CoreSession::updateBufferInfo(UserId uid, const BufferInfo &bufinfo) {
- if(uid == user()) emit bufferInfoUpdated(bufinfo);
-}
-
-void CoreSession::connectToNetwork(NetworkId id) {
- CoreNetwork *net = network(id);
- if(!net) {
- qWarning() << "Connect to unknown network requested! net:" << id << "user:" << user();
- return;
- }
-
- NetworkConnection *conn = networkConnection(id);
- if(!conn) {
- conn = new NetworkConnection(net, this);
- _connections[id] = conn;
- attachNetworkConnection(conn);
- }
- conn->connectToIrc();
-}
-
-void CoreSession::attachNetworkConnection(NetworkConnection *conn) {
- connect(conn, SIGNAL(connected(NetworkId)), this, SLOT(networkConnected(NetworkId)));
- connect(conn, SIGNAL(quitRequested(NetworkId)), this, SLOT(networkDisconnected(NetworkId)));
-
- // I guess we don't need these anymore, client-side can just connect the network's signals directly
- //signalProxy()->attachSignal(conn, SIGNAL(connected(NetworkId)), SIGNAL(networkConnected(NetworkId)));
- //signalProxy()->attachSignal(conn, SIGNAL(disconnected(NetworkId)), SIGNAL(networkDisconnected(NetworkId)));
-
- connect(conn, SIGNAL(displayMsg(Message::Type, BufferInfo::Type, QString, QString, QString, Message::Flags)),
- this, SLOT(recvMessageFromServer(Message::Type, BufferInfo::Type, QString, QString, QString, Message::Flags)));
- connect(conn, SIGNAL(displayStatusMsg(QString)), this, SLOT(recvStatusMsgFromServer(QString)));
-
- connect(conn, SIGNAL(nickChanged(const NetworkId &, const QString &, const QString &)),
- this, SLOT(renameBuffer(const NetworkId &, const QString &, const QString &)));
- connect(conn, SIGNAL(channelJoined(NetworkId, const QString &, const QString &)),
- this, SLOT(channelJoined(NetworkId, const QString &, const QString &)));
- connect(conn, SIGNAL(channelParted(NetworkId, const QString &)),
- this, SLOT(channelParted(NetworkId, const QString &)));
-}
-
-void CoreSession::disconnectFromNetwork(NetworkId id) {
- if(!_connections.contains(id))
- return;
-
- //_connections[id]->disconnectFromIrc();
- _connections[id]->userInputHandler()->handleQuit(BufferInfo(), QString());
-}
-
-void CoreSession::networkStateRequested() {
-}
-
void CoreSession::addClient(QIODevice *device) {
if(!device) {
qCritical() << "Invoking CoreSession::addClient with a QObject that is not a QIODevice!";
quInfo() << qPrintable(tr("Client")) << qPrintable(socket->peerAddress().toString()) << qPrintable(tr("disconnected (UserId: %1).").arg(user().toInt()));
}
-SignalProxy *CoreSession::signalProxy() const {
- return _signalProxy;
-}
-
-// FIXME we need a sane way for creating buffers!
-void CoreSession::networkConnected(NetworkId networkid) {
- Core::bufferInfo(user(), networkid, BufferInfo::StatusBuffer); // create status buffer
- Core::setNetworkConnected(user(), networkid, true);
-}
-
-// called now only on /quit and requested disconnects, not on normal disconnects!
-void CoreSession::networkDisconnected(NetworkId networkid) {
- // if the network has already been removed, we don't have a networkconnection left either, so we don't do anything
- // make sure to not depend on the network still existing when calling this function!
- if(_connections.contains(networkid)) {
- Core::setNetworkConnected(user(), networkid, false);
- _connections.take(networkid)->deleteLater();
- }
-}
-
-void CoreSession::channelJoined(NetworkId id, const QString &channel, const QString &key) {
- Core::setChannelPersistent(user(), id, channel, true);
- Core::setPersistentChannelKey(user(), id, channel, key);
-}
-
-void CoreSession::channelParted(NetworkId id, const QString &channel) {
- Core::setChannelPersistent(user(), id, channel, false);
-}
-
QHash<QString, QString> CoreSession::persistentChannels(NetworkId id) const {
return Core::persistentChannels(user(), id);
return QHash<QString, QString>();
// FIXME switch to BufferId
void CoreSession::msgFromClient(BufferInfo bufinfo, QString msg) {
- NetworkConnection *conn = networkConnection(bufinfo.networkId());
- if(conn) {
- conn->userInput(bufinfo, msg);
+ CoreNetwork *net = network(bufinfo.networkId());
+ if(net) {
+ net->userInput(bufinfo, msg);
} else {
qWarning() << "Trying to send to unconnected network:" << msg;
}
// So this is the perfect place for storing the backlog and log stuff.
void CoreSession::recvMessageFromServer(Message::Type type, BufferInfo::Type bufferType,
QString target, QString text, QString sender, Message::Flags flags) {
- NetworkConnection *netCon = qobject_cast<NetworkConnection*>(this->sender());
- Q_ASSERT(netCon);
+ CoreNetwork *net = qobject_cast<CoreNetwork*>(this->sender());
+ Q_ASSERT(net);
- BufferInfo bufferInfo = Core::bufferInfo(user(), netCon->networkId(), bufferType, target);
+ BufferInfo bufferInfo = Core::bufferInfo(user(), net->networkId(), bufferType, target);
Message msg(bufferInfo, type, text, sender, flags);
msg.setMsgId(Core::storeMessage(msg));
Q_ASSERT(msg.msgId() != 0);
}
void CoreSession::recvStatusMsgFromServer(QString msg) {
- NetworkConnection *s = qobject_cast<NetworkConnection*>(sender());
- Q_ASSERT(s);
- emit displayStatusMsg(s->networkName(), msg);
+ CoreNetwork *net = qobject_cast<CoreNetwork*>(sender());
+ Q_ASSERT(net);
+ emit displayStatusMsg(net->networkName(), msg);
}
QList<BufferInfo> CoreSession::buffers() const {
id = info.networkId.toInt();
if(!_networks.contains(id)) {
CoreNetwork *net = new CoreNetwork(id, this);
- connect(net, SIGNAL(connectRequested(NetworkId)), this, SLOT(connectToNetwork(NetworkId)));
- connect(net, SIGNAL(disconnectRequested(NetworkId)), this, SLOT(disconnectFromNetwork(NetworkId)));
+ connect(net, SIGNAL(displayMsg(Message::Type, BufferInfo::Type, QString, QString, QString, Message::Flags)),
+ this, SLOT(recvMessageFromServer(Message::Type, BufferInfo::Type, QString, QString, QString, Message::Flags)));
+ connect(net, SIGNAL(displayStatusMsg(QString)), this, SLOT(recvStatusMsgFromServer(QString)));
+
net->setNetworkInfo(info);
net->setProxy(signalProxy());
_networks[id] = net;
void CoreSession::removeNetwork(NetworkId id) {
// Make sure the network is disconnected!
- NetworkConnection *conn = _connections.value(id, 0);
- if(conn) {
- if(conn->connectionState() != Network::Disconnected) {
- connect(conn, SIGNAL(disconnected(NetworkId)), this, SLOT(destroyNetwork(NetworkId)));
- conn->disconnectFromIrc();
- } else {
- _connections.take(id)->deleteLater(); // TODO make this saner
- destroyNetwork(id);
- }
+ CoreNetwork *net = network(id);
+ if(!net)
+ return;
+
+ if(net->connectionState() != Network::Disconnected) {
+ connect(net, SIGNAL(disconnected(NetworkId)), this, SLOT(destroyNetwork(NetworkId)));
+ net->disconnectFromIrc();
} else {
destroyNetwork(id);
}
}
void CoreSession::destroyNetwork(NetworkId id) {
- if(_connections.contains(id)) {
- // this can happen if the network was reconnecting while being removed
- _connections.take(id)->deleteLater();
- }
QList<BufferId> removedBuffers = Core::requestBufferIdsForNetwork(user(), id);
Network *net = _networks.take(id);
if(net && Core::removeNetwork(user(), id)) {
emit bufferRemoved(bufferId);
}
+// FIXME: use a coreBufferSyncer for this
void CoreSession::renameBuffer(const NetworkId &networkId, const QString &newName, const QString &oldName) {
BufferId bufferId = Core::renameBuffer(user(), networkId, newName, oldName);
if(bufferId.isValid()) {
}
void CoreSession::clientsConnected() {
- QHash<NetworkId, NetworkConnection *>::iterator conIter = _connections.begin();
+ QHash<NetworkId, CoreNetwork *>::iterator netIter = _networks.begin();
Identity *identity = 0;
- NetworkConnection *con = 0;
- Network *network = 0;
+ CoreNetwork *net = 0;
IrcUser *me = 0;
QString awayReason;
- while(conIter != _connections.end()) {
- con = *conIter;
- conIter++;
+ while(netIter != _networks.end()) {
+ net = *netIter;
+ netIter++;
- if(!con->isConnected())
+ if(!net->isConnected())
continue;
- identity = con->identity();
+ identity = net->identityPtr();
if(!identity)
continue;
- network = con->network();
- if(!network)
- continue;
- me = network->me();
+ me = net->me();
if(!me)
continue;
if(identity->detachAwayEnabled() && me->isAway()) {
- con->userInputHandler()->handleAway(BufferInfo(), QString());
+ net->userInputHandler()->handleAway(BufferInfo(), QString());
}
}
}
void CoreSession::clientsDisconnected() {
- QHash<NetworkId, NetworkConnection *>::iterator conIter = _connections.begin();
+ QHash<NetworkId, CoreNetwork *>::iterator netIter = _networks.begin();
Identity *identity = 0;
- NetworkConnection *con = 0;
- Network *network = 0;
+ CoreNetwork *net = 0;
IrcUser *me = 0;
QString awayReason;
- while(conIter != _connections.end()) {
- con = *conIter;
- conIter++;
+ while(netIter != _networks.end()) {
+ net = *netIter;
+ netIter++;
- if(!con->isConnected())
+ if(!net->isConnected())
continue;
- identity = con->identity();
+ identity = net->identityPtr();
if(!identity)
continue;
- network = con->network();
- if(!network)
- continue;
- me = network->me();
+ me = net->me();
if(!me)
continue;
awayReason = identity->detachAwayReason();
else
awayReason = identity->awayReason();
- network->setAutoAwayActive(true);
- con->userInputHandler()->handleAway(BufferInfo(), awayReason);
+ net->setAutoAwayActive(true);
+ net->userInputHandler()->handleAway(BufferInfo(), awayReason);
}
}
}
QVariant sessionState();
- SignalProxy *signalProxy() const;
+ inline SignalProxy *signalProxy() const { return _signalProxy; }
const AliasManager &aliasManager() const { return _aliasManager; }
AliasManager &aliasManager() { return _aliasManager; }
inline CoreIrcListHelper *ircListHelper() const { return _ircListHelper; }
- void attachNetworkConnection(NetworkConnection *conn);
+// void attachNetworkConnection(NetworkConnection *conn);
//! Return necessary data for restoring the session after restarting the core
void saveSessionState() const;
void restoreSessionState();
public slots:
- void networkStateRequested();
-
void addClient(QIODevice *device);
void addClient(SignalProxy *proxy);
- void connectToNetwork(NetworkId);
- void disconnectFromNetwork(NetworkId id);
-
void msgFromClient(BufferInfo, QString message);
//! Create an identity and propagate the changes to the clients.
*/
void renameBuffer(const NetworkId &networkId, const QString &newName, const QString &oldName);
- void channelJoined(NetworkId id, const QString &channel, const QString &key = QString());
- void channelParted(NetworkId, const QString &channel);
QHash<QString, QString> persistentChannels(NetworkId) const;
signals:
void displayMsg(Message message);
void displayStatusMsg(QString, QString);
- //void connectToIrc(QString net);
- //void disconnectFromIrc(QString net);
-
- void bufferInfoUpdated(BufferInfo);
-
void scriptResult(QString result);
//! Identity has been created.
void recvStatusMsgFromServer(QString msg);
void recvMessageFromServer(Message::Type, BufferInfo::Type, QString target, QString text, QString sender = "", Message::Flags flags = Message::None);
- void networkConnected(NetworkId networkid);
- void networkDisconnected(NetworkId networkid);
void destroyNetwork(NetworkId);
void identityUpdated(const QVariantMap &);
- //! Called when storage updated a BufferInfo.
- /** This emits bufferInfoUpdated() via SignalProxy, iff it's one of our buffers.
- * \param user The buffer's owner (not necessarily us)
- * \param bufferInfo The updated BufferInfo
- */
- void updateBufferInfo(UserId user, const BufferInfo &bufferInfo);
-
void storeBufferLastSeenMsg(BufferId buffer, const MsgId &msgId);
void scriptRequest(QString script);
SignalProxy *_signalProxy;
CoreAliasManager _aliasManager;
- QHash<NetworkId, NetworkConnection *> _connections;
+ // QHash<NetworkId, NetworkConnection *> _connections;
QHash<NetworkId, CoreNetwork *> _networks;
// QHash<NetworkId, CoreNetwork *> _networksToRemove;
QHash<IdentityId, Identity *> _identities;
#include "quassel.h"
#include "util.h"
-CtcpHandler::CtcpHandler(NetworkConnection *parent)
+CtcpHandler::CtcpHandler(CoreNetwork *parent)
: BasicHandler(parent),
XDELIM("\001")
{
Q_OBJECT
public:
- CtcpHandler(NetworkConnection *parent = 0);
+ CtcpHandler(CoreNetwork *parent = 0);
enum CtcpType {CtcpQuery, CtcpReply};
#include "coresession.h"
#include "coreirclisthelper.h"
-#include "networkconnection.h"
-#include "network.h"
#include "identity.h"
#include "ctcphandler.h"
#include <QDebug>
-IrcServerHandler::IrcServerHandler(NetworkConnection *parent)
+IrcServerHandler::IrcServerHandler(CoreNetwork *parent)
: BasicHandler(parent),
_whois(false)
{
// many nets define their own WHOIS fields. we fetch those not in need of special attention here:
emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", "[Whois] " + params.join(" "), prefix);
} else {
- if(networkConnection()->coreSession()->ircListHelper()->requestInProgress(network()->networkId()))
- networkConnection()->coreSession()->ircListHelper()->reportError(params.join(" "));
+ if(coreSession()->ircListHelper()->requestInProgress(network()->networkId()))
+ coreSession()->ircListHelper()->reportError(params.join(" "));
else
emit displayMsg(Message::Error, BufferInfo::StatusBuffer, "", cmd + " " + params.join(" "), prefix);
}
//qDebug() << "IrcServerHandler::handleJoin()" << prefix << params;
ircuser->joinChannel(channel);
if(network()->isMe(ircuser)) {
- networkConnection()->setChannelJoined(channel);
+ network()->setChannelJoined(channel);
putCmd("MODE", params[0]); // we want to know the modes of the channel we just joined, so we ask politely
}
}
msg = victim->nick();
emit displayMsg(Message::Kick, BufferInfo::ChannelBuffer, channel, msg, prefix);
- //if(network()->isMe(victim)) networkConnection()->setKickedFromChannel(channel);
+ //if(network()->isMe(victim)) network()->setKickedFromChannel(channel);
}
void IrcServerHandler::handleMode(const QString &prefix, const QList<QByteArray> ¶ms) {
? newnick
: prefix;
- emit nickChanged(newnick, oldnick);
+ coreSession()->renameBuffer(network()->networkId(), newnick, oldnick);
foreach(QString channel, ircuser->channels())
emit displayMsg(Message::Nick, BufferInfo::ChannelBuffer, channel, newnick, sender);
target = nickFromMask(prefix);
}
- networkConnection()->ctcpHandler()->parse(Message::Notice, prefix, target, params[1]);
+ network()->ctcpHandler()->parse(Message::Notice, prefix, target, params[1]);
}
void IrcServerHandler::handlePart(const QString &prefix, const QList<QByteArray> ¶ms) {
msg = userDecode(ircuser->nick(), params[1]);
emit displayMsg(Message::Part, BufferInfo::ChannelBuffer, channel, msg, prefix);
- if(network()->isMe(ircuser)) networkConnection()->setChannelParted(channel);
+ if(network()->isMe(ircuser)) network()->setChannelParted(channel);
}
void IrcServerHandler::handlePing(const QString &prefix, const QList<QByteArray> ¶ms) {
// it's possible to pack multiple privmsgs into one param using ctcp
// - > we let the ctcpHandler do the work
- networkConnection()->ctcpHandler()->parse(Message::Plain, prefix, target, msg);
+ network()->ctcpHandler()->parse(Message::Plain, prefix, target, msg);
}
void IrcServerHandler::handleQuit(const QString &prefix, const QList<QByteArray> ¶ms) {
return;
QStringList p = serverDecode(params);
- if(networkConnection()->setAutoWhoDone(p[0])) {
+ if(network()->setAutoWhoDone(p[0])) {
return; // stay silent
}
p.takeLast(); // should be "End of WHO list"
default:
break;
}
- if(!networkConnection()->coreSession()->ircListHelper()->addChannel(network()->networkId(), channelName, userCount, topic))
+ if(!coreSession()->ircListHelper()->addChannel(network()->networkId(), channelName, userCount, topic))
emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("Channel %1 has %2 users. Topic is: %3").arg(channelName).arg(userCount).arg(topic));
}
Q_UNUSED(prefix)
Q_UNUSED(params)
- if(!networkConnection()->coreSession()->ircListHelper()->endOfChannelList(network()->networkId()))
+ if(!coreSession()->ircListHelper()->endOfChannelList(network()->networkId()))
emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("End of channel list"));
}
ircuser->setRealName(serverDecode(params.last()).section(" ", 1));
}
- if(!networkConnection()->isAutoWhoInProgress(channel)) {
+ if(!network()->isAutoWhoInProgress(channel)) {
emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("[Who] %1").arg(serverDecode(params).join(" ")));
}
}
/* */
void IrcServerHandler::tryNextNick(const QString &errnick) {
- QStringList desiredNicks = networkConnection()->coreSession()->identity(network()->identity())->nicks();
+ QStringList desiredNicks = coreSession()->identity(network()->identity())->nicks();
int nextNick = desiredNicks.indexOf(errnick) + 1;
if(desiredNicks.size() > nextNick) {
putCmd("NICK", serverEncode(desiredNicks[nextNick]));
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
-#ifndef _IRCSERVERHANDLER_H_
-#define _IRCSERVERHANDLER_H_
+#ifndef IRCSERVERHANDLER_H
+#define IRCSERVERHANDLER_H
#include "basichandler.h"
Q_OBJECT
public:
- IrcServerHandler(NetworkConnection *parent);
+ IrcServerHandler(CoreNetwork *parent);
~IrcServerHandler();
void handleServerMsg(QByteArray rawMsg);
void defaultHandler(QString cmd, const QString &prefix, const QList<QByteArray> ¶ms);
-signals:
- void nickChanged(const QString &newNick, const QString &oldNick); // this signal is inteded to rename query buffers in the storage backend
-
private:
void tryNextNick(const QString &errnick);
bool checkParamCount(const QString &methodName, const QList<QByteArray> ¶ms, int minParams);
+++ /dev/null
-/***************************************************************************
- * Copyright (C) 2005-08 by the Quassel Project *
- * devel@quassel-irc.org *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) version 3. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the *
- * Free Software Foundation, Inc., *
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
- ***************************************************************************/
-#include "networkconnection.h"
-
-#include <QMetaObject>
-#include <QMetaMethod>
-#include <QDateTime>
-
-#include "util.h"
-#include "core.h"
-#include "coresession.h"
-
-#include "ircchannel.h"
-#include "ircuser.h"
-#include "identity.h"
-
-#include "ircserverhandler.h"
-#include "userinputhandler.h"
-#include "ctcphandler.h"
-
-#include "logger.h"
-
-NetworkConnection::NetworkConnection(Network *network, CoreSession *session)
- : QObject(network),
- _connectionState(Network::Disconnected),
- _network(network),
- _coreSession(session),
- _ircServerHandler(new IrcServerHandler(this)),
- _userInputHandler(new UserInputHandler(this)),
- _ctcpHandler(new CtcpHandler(this)),
- _autoReconnectCount(0),
- _quitRequested(false),
-
- _previousConnectionAttemptFailed(false),
- _lastUsedServerlistIndex(0),
-
- // TODO make autowho configurable (possibly per-network)
- _autoWhoEnabled(true),
- _autoWhoInterval(90),
- _autoWhoNickLimit(0), // unlimited
- _autoWhoDelay(3),
-
- // TokenBucket to avaid sending too much at once
- _messagesPerSecond(1),
- _burstSize(5),
- _tokenBucket(5) // init with a full bucket
-{
- _autoReconnectTimer.setSingleShot(true);
- _socketCloseTimer.setSingleShot(true);
- connect(&_socketCloseTimer, SIGNAL(timeout()), this, SLOT(socketCloseTimeout()));
-
- _pingTimer.setInterval(60000);
- connect(&_pingTimer, SIGNAL(timeout()), this, SLOT(sendPing()));
-
- _autoWhoTimer.setInterval(_autoWhoDelay * 1000);
- _autoWhoCycleTimer.setInterval(_autoWhoInterval * 1000);
-
- _tokenBucketTimer.start(_messagesPerSecond * 1000);
-
- QHash<QString, QString> channels = coreSession()->persistentChannels(networkId());
- foreach(QString chan, channels.keys()) {
- _channelKeys[chan.toLower()] = channels[chan];
- }
-
- 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(network, SIGNAL(currentServerSet(const QString &)), this, SLOT(networkInitialized(const QString &)));
- connect(network, SIGNAL(useAutoReconnectSet(bool)), this, SLOT(autoReconnectSettingsChanged()));
- connect(network, SIGNAL(autoReconnectIntervalSet(quint32)), this, SLOT(autoReconnectSettingsChanged()));
- connect(network, SIGNAL(autoReconnectRetriesSet(quint16)), this, SLOT(autoReconnectSettingsChanged()));
-
-#ifdef HAVE_SSL
- connect(&socket, SIGNAL(encrypted()), this, SLOT(socketEncrypted()));
- connect(&socket, SIGNAL(sslErrors(const QList<QSslError> &)), this, SLOT(sslErrors(const QList<QSslError> &)));
-#endif
- connect(&socket, SIGNAL(connected()), this, SLOT(socketConnected()));
-
- 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()));
-
- connect(_ircServerHandler, SIGNAL(nickChanged(const QString &, const QString &)),
- this, SLOT(nickChanged(const QString &, const QString &)));
-
- network->proxy()->attachSignal(this, SIGNAL(sslErrors(const QVariant &)));
-}
-
-NetworkConnection::~NetworkConnection() {
- if(connectionState() != Network::Disconnected && connectionState() != Network::Reconnecting)
- disconnectFromIrc(false); // clean up, but this does not count as requested disconnect!
- disconnect(&socket, 0, this, 0); // this keeps the socket from triggering events during clean up
- delete _ircServerHandler;
- delete _userInputHandler;
- delete _ctcpHandler;
-}
-
-void NetworkConnection::setConnectionState(Network::ConnectionState state) {
- _connectionState = state;
- network()->setConnectionState(state);
- emit connectionStateChanged(state);
-}
-
-QString NetworkConnection::serverDecode(const QByteArray &string) const {
- return network()->decodeServerString(string);
-}
-
-QString NetworkConnection::channelDecode(const QString &bufferName, const QByteArray &string) const {
- if(!bufferName.isEmpty()) {
- IrcChannel *channel = network()->ircChannel(bufferName);
- if(channel) return channel->decodeString(string);
- }
- return network()->decodeString(string);
-}
-
-QString NetworkConnection::userDecode(const QString &userNick, const QByteArray &string) const {
- IrcUser *user = network()->ircUser(userNick);
- if(user) return user->decodeString(string);
- return network()->decodeString(string);
-}
-
-QByteArray NetworkConnection::serverEncode(const QString &string) const {
- return network()->encodeServerString(string);
-}
-
-QByteArray NetworkConnection::channelEncode(const QString &bufferName, const QString &string) const {
- if(!bufferName.isEmpty()) {
- IrcChannel *channel = network()->ircChannel(bufferName);
- if(channel) return channel->encodeString(string);
- }
- return network()->encodeString(string);
-}
-
-QByteArray NetworkConnection::userEncode(const QString &userNick, const QString &string) const {
- IrcUser *user = network()->ircUser(userNick);
- if(user) return user->encodeString(string);
- return network()->encodeString(string);
-}
-
-void NetworkConnection::autoReconnectSettingsChanged() {
- if(!network()->useAutoReconnect()) {
- _autoReconnectTimer.stop();
- _autoReconnectCount = 0;
- } else {
- _autoReconnectTimer.setInterval(network()->autoReconnectInterval() * 1000);
- if(_autoReconnectCount != 0) {
- if(network()->unlimitedReconnectRetries()) _autoReconnectCount = -1;
- else _autoReconnectCount = network()->autoReconnectRetries();
- }
- }
-}
-
-void NetworkConnection::connectToIrc(bool reconnecting) {
- if(!reconnecting && network()->useAutoReconnect() && _autoReconnectCount == 0) {
- _autoReconnectTimer.setInterval(network()->autoReconnectInterval() * 1000);
- if(network()->unlimitedReconnectRetries()) _autoReconnectCount = -1;
- else _autoReconnectCount = network()->autoReconnectRetries();
- }
- QVariantList serverList = network()->serverList();
- Identity *identity = coreSession()->identity(network()->identity());
- if(!serverList.count()) {
- qWarning() << "Server list empty, ignoring connect request!";
- return;
- }
- if(!identity) {
- qWarning() << "Invalid identity configures, ignoring connect request!";
- return;
- }
- // use a random server?
- if(network()->useRandomServer()) {
- _lastUsedServerlistIndex = 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(++_lastUsedServerlistIndex == serverList.size()) {
- _lastUsedServerlistIndex = 0;
- }
- }
- _previousConnectionAttemptFailed = false;
-
- QString host = serverList[_lastUsedServerlistIndex].toMap()["Host"].toString();
- quint16 port = serverList[_lastUsedServerlistIndex].toMap()["Port"].toUInt();
- displayStatusMsg(tr("Connecting to %1:%2...").arg(host).arg(port));
- displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("Connecting to %1:%2...").arg(host).arg(port));
- socket.connectToHost(host, port);
-}
-
-void NetworkConnection::networkInitialized(const QString ¤tServer) {
- if(currentServer.isEmpty()) return;
-
- if(network()->useAutoReconnect() && !network()->unlimitedReconnectRetries()) {
- _autoReconnectCount = network()->autoReconnectRetries(); // reset counter
- }
-
- sendPerform();
-
- // now we are initialized
- setConnectionState(Network::Initialized);
- network()->setConnected(true);
- emit connected(networkId());
-
- _pingTimer.start();
-
- if(_autoWhoEnabled) {
- _autoWhoCycleTimer.start();
- _autoWhoTimer.start();
- startAutoWhoCycle(); // FIXME wait for autojoin to be completed
- }
-}
-
-void NetworkConnection::sendPerform() {
- BufferInfo statusBuf = Core::bufferInfo(coreSession()->user(), network()->networkId(), BufferInfo::StatusBuffer);
- // do auto identify
- if(network()->useAutoIdentify() && !network()->autoIdentifyService().isEmpty() && !network()->autoIdentifyPassword().isEmpty()) {
- userInputHandler()->handleMsg(statusBuf, QString("%1 IDENTIFY %2").arg(network()->autoIdentifyService(), network()->autoIdentifyPassword()));
- }
- // send perform list
- foreach(QString line, network()->perform()) {
- if(!line.isEmpty()) userInput(statusBuf, line);
- }
-
- // 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);
- }
- }
- QString joinString = QString("%1 %2").arg(channels.join(",")).arg(keys.join(",")).trimmed();
- if(!joinString.isEmpty()) userInputHandler()->handleJoin(statusBuf, joinString);
-}
-
-void NetworkConnection::disconnectFromIrc(bool requested, const QString &reason) {
- _quitRequested = requested; // see socketDisconnected();
- _autoReconnectTimer.stop();
- _autoReconnectCount = 0; // prohibiting auto reconnect
- 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();
- 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);
- }
-}
-
-void NetworkConnection::socketHasData() {
- while(socket.canReadLine()) {
- QByteArray s = socket.readLine().trimmed();
- ircServerHandler()->handleServerMsg(s);
- }
-}
-
-void NetworkConnection::socketError(QAbstractSocket::SocketError) {
- _previousConnectionAttemptFailed = true;
- qWarning() << qPrintable(tr("Could not connect to %1 (%2)").arg(network()->networkName(), socket.errorString()));
- emit connectionError(socket.errorString());
- emit displayMsg(Message::Error, BufferInfo::StatusBuffer, "", tr("Connection failure: %1").arg(socket.errorString()));
- network()->emitConnectionError(socket.errorString());
- if(socket.state() < QAbstractSocket::ConnectedState) {
- socketDisconnected();
- }
- // mark last connection attempt as failed
-
- //qDebug() << "exiting...";
- //exit(1);
-}
-
-#ifdef HAVE_SSL
-
-void NetworkConnection::sslErrors(const QList<QSslError> &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();
- */
-}
-
-void NetworkConnection::socketEncrypted() {
- //qDebug() << "encrypted!";
- socketInitialized();
-}
-
-#endif // HAVE_SSL
-
-void NetworkConnection::socketConnected() {
-#ifndef HAVE_SSL
- socketInitialized();
- return;
-#else
- if(!network()->serverList()[_lastUsedServerlistIndex].toMap()["UseSSL"].toBool()) {
- socketInitialized();
- return;
- }
- //qDebug() << "starting handshake";
- socket.startClientEncryption();
-#endif
-}
-
-void NetworkConnection::socketInitialized() {
- //emit connected(networkId()); initialize first!
- Identity *identity = coreSession()->identity(network()->identity());
- if(!identity) {
- qCritical() << "Identity invalid!";
- disconnectFromIrc();
- return;
- }
- QString passwd = network()->serverList()[_lastUsedServerlistIndex].toMap()["Password"].toString();
- if(!passwd.isEmpty()) {
- putRawLine(serverEncode(QString("PASS %1").arg(passwd)));
- }
- putRawLine(serverEncode(QString("NICK :%1").arg(identity->nicks()[0]))); // FIXME: try more nicks if error occurs
- putRawLine(serverEncode(QString("USER %1 8 * :%2").arg(identity->ident(), identity->realName())));
-}
-
-void NetworkConnection::socketStateChanged(QAbstractSocket::SocketState socketState) {
- Network::ConnectionState state;
- switch(socketState) {
- case QAbstractSocket::UnconnectedState:
- state = Network::Disconnected;
- break;
- case QAbstractSocket::HostLookupState:
- case QAbstractSocket::ConnectingState:
- state = Network::Connecting;
- break;
- case QAbstractSocket::ConnectedState:
- state = Network::Initializing;
- break;
- case QAbstractSocket::ClosingState:
- state = Network::Disconnecting;
- break;
- default:
- state = Network::Disconnected;
- }
- setConnectionState(state);
-}
-
-void NetworkConnection::socketCloseTimeout() {
- socket.disconnectFromHost();
-}
-
-void NetworkConnection::socketDisconnected() {
- _pingTimer.stop();
- _autoWhoCycleTimer.stop();
- _autoWhoTimer.stop();
- _autoWhoQueue.clear();
- _autoWhoInProgress.clear();
-
- _socketCloseTimer.stop();
-
- IrcUser *me = network()->me();
- if(me) {
- foreach(QString channel, me->channels())
- emit displayMsg(Message::Quit, BufferInfo::ChannelBuffer, channel, "", me->hostmask());
- }
-
- network()->setConnected(false);
- emit disconnected(networkId());
- if(_quitRequested) {
- setConnectionState(Network::Disconnected);
- emit quitRequested(networkId());
- } else if(_autoReconnectCount != 0) {
- setConnectionState(Network::Reconnecting);
- if(_autoReconnectCount == network()->autoReconnectRetries())
- doAutoReconnect(); // first try is immediate
- else
- _autoReconnectTimer.start();
- }
-}
-
-void NetworkConnection::doAutoReconnect() {
- if(connectionState() != Network::Disconnected && connectionState() != Network::Reconnecting) {
- qWarning() << "NetworkConnection::doAutoReconnect(): Cannot reconnect while not being disconnected!";
- return;
- }
- if(_autoReconnectCount > 0) _autoReconnectCount--;
- connectToIrc(true);
-}
-
-// FIXME switch to BufferId
-void NetworkConnection::userInput(BufferInfo buf, QString msg) {
- userInputHandler()->handleUserInput(buf, msg);
-}
-
-void NetworkConnection::putRawLine(QByteArray s) {
- if(_tokenBucket > 0) {
- // qDebug() << "putRawLine: " << s;
- writeToSocket(s);
- } else {
- _msgQueue.append(s);
- }
-}
-
-void NetworkConnection::writeToSocket(QByteArray s) {
- s += "\r\n";
- // qDebug() << "writeToSocket: " << s.size();
- socket.write(s);
- _tokenBucket--;
-}
-
-void NetworkConnection::fillBucketAndProcessQueue() {
- if(_tokenBucket < _burstSize) {
- _tokenBucket++;
- }
-
- while(_msgQueue.size() > 0 && _tokenBucket > 0) {
- writeToSocket(_msgQueue.takeFirst());
- }
-}
-
-// returns 0 if the message will not be chopped by the irc server or number of chopped bytes if message is too long
-int NetworkConnection::lastParamOverrun(const QString &cmd, const QList<QByteArray> ¶ms) {
- //the server will pass our message that trunkated to 512 bytes including CRLF with the following format:
- // ":prefix COMMAND param0 param1 :lastparam"
- // where prefix = "nickname!user@host"
- // that means that the last message can be as long as:
- // 512 - nicklen - userlen - hostlen - commandlen - sum(param[0]..param[n-1])) - 2 (for CRLF) - 4 (":!@" + 1space between prefix and command) - max(paramcount - 1, 0) (space for simple params) - 2 (space and colon for last param)
- IrcUser *me = network()->me();
- int maxLen = 480 - cmd.toAscii().count(); // educated guess in case we don't know us (yet?)
-
- if(me)
- maxLen = 512 - serverEncode(me->nick()).count() - serverEncode(me->user()).count() - serverEncode(me->host()).count() - cmd.toAscii().count() - 6;
-
- if(!params.isEmpty()) {
- for(int i = 0; i < params.count() - 1; i++) {
- maxLen -= (params[i].count() + 1);
- }
- maxLen -= 2; // " :" last param separator;
-
- if(params.last().count() > maxLen) {
- return params.last().count() - maxLen;
- } else {
- return 0;
- }
- } else {
- return 0;
- }
-}
-
-void NetworkConnection::putCmd(const QString &cmd, const QList<QByteArray> ¶ms, const QByteArray &prefix) {
- QByteArray msg;
- if(cmd == "PRIVMSG" && params.count() > 1) {
- int overrun = lastParamOverrun(cmd, params);
- if(overrun) {
- QList<QByteArray> paramCopy1 = params;
- paramCopy1.removeLast();
- QList<QByteArray> paramCopy2 = paramCopy1;
-
- QByteArray lastPart = params.last();
- QByteArray splitter(" .,-");
- int maxSplitPos = params.last().count() - overrun;
- int splitPos = -1;
- for(int i = 0; i < splitter.size(); i++) {
- splitPos = qMax(splitPos, lastPart.lastIndexOf(splitter[i], maxSplitPos));
- }
- if(splitPos <= 0) {
- splitPos = maxSplitPos;
- }
-
- paramCopy1 << lastPart.left(splitPos);
- paramCopy2 << lastPart.mid(splitPos);
- putCmd(cmd, paramCopy1, prefix);
- putCmd(cmd, paramCopy2, prefix);
- return;
- }
- }
-
- if(!prefix.isEmpty())
- msg += ":" + prefix + " ";
- msg += cmd.toUpper().toAscii();
-
- for(int i = 0; i < params.size() - 1; i++) {
- msg += " " + params[i];
- }
- if(!params.isEmpty())
- msg += " :" + params.last();
-
- putRawLine(msg);
-}
-
-void NetworkConnection::sendPing() {
- userInputHandler()->handlePing(BufferInfo(), QString());
-}
-
-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[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) {
- if(_autoWhoInProgress.value(channel.toLower(), 0) <= 0) return false;
- _autoWhoInProgress[channel.toLower()]--;
- return true;
-}
-
-void NetworkConnection::setChannelJoined(const QString &channel) {
- emit channelJoined(networkId(), channel, _channelKeys[channel.toLower()]);
- _autoWhoQueue.prepend(channel.toLower()); // prepend so this new chan is the first to be checked
-}
-
-void NetworkConnection::setChannelParted(const QString &channel) {
- removeChannelKey(channel);
- _autoWhoQueue.removeAll(channel.toLower());
- _autoWhoInProgress.remove(channel.toLower());
- emit channelParted(networkId(), channel);
-}
-
-void NetworkConnection::addChannelKey(const QString &channel, const QString &key) {
- if(key.isEmpty()) {
- removeChannelKey(channel);
- } else {
- _channelKeys[channel.toLower()] = key;
- }
-}
-
-void NetworkConnection::removeChannelKey(const QString &channel) {
- _channelKeys.remove(channel.toLower());
-}
-
-void NetworkConnection::nickChanged(const QString &newNick, const QString &oldNick) {
- emit nickChanged(networkId(), newNick, oldNick);
-}
-
-/* Exception classes for message handling */
-NetworkConnection::ParseError::ParseError(QString cmd, QString prefix, QStringList params) {
- Q_UNUSED(prefix);
- _msg = QString("Command Parse Error: ") + cmd + params.join(" ");
-}
-
-NetworkConnection::UnknownCmdError::UnknownCmdError(QString cmd, QString prefix, QStringList params) {
- Q_UNUSED(prefix);
- _msg = QString("Unknown Command: ") + cmd + params.join(" ");
-}
-
+++ /dev/null
-/***************************************************************************
- * Copyright (C) 2005-08 by the Quassel Project *
- * devel@quassel-irc.org *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) version 3. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the *
- * Free Software Foundation, Inc., *
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
- ***************************************************************************/
-
-#ifndef _NETWORKCONNECTION_H_
-#define _NETWORKCONNECTION_H_
-
-#include <QAbstractSocket>
-#include <QString>
-#include <QStringList>
-#include <QTimer>
-
-#ifdef HAVE_SSL
-# include <QSslSocket>
-# include <QSslError>
-#else
-# include <QTcpSocket>
-#endif
-
-#include "coresession.h"
-#include "identity.h"
-#include "message.h"
-#include "network.h"
-#include "signalproxy.h"
-
-class IrcServerHandler;
-class UserInputHandler;
-class CtcpHandler;
-
-class NetworkConnection : public QObject {
- Q_OBJECT
-
-public:
- NetworkConnection(Network *network, CoreSession *session);
- ~NetworkConnection();
-
- 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; }
-
- inline bool isConnected() const { return connectionState() == Network::Initialized; }
- inline Network::ConnectionState connectionState() const { return _connectionState; }
-
- 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;
-
- //! Decode a string using a channel-specific encoding if one is set (and use the standard encoding else).
- QString channelDecode(const QString &channelName, const QByteArray &string) const;
-
- //! Decode a string using an IrcUser-specific encoding, if one exists (using the standaed encoding else).
- QString userDecode(const QString &userNick, const QByteArray &string) const;
-
- //! Encode a string using the server (network) encoding.
- QByteArray serverEncode(const QString &string) const;
-
- //! Encode a string using the channel-specific encoding, if set, and use the standard encoding else.
- QByteArray channelEncode(const QString &channelName, const QString &string) const;
-
- //! Encode a string using the user-specific encoding, if set, and use the standard encoding else.
- QByteArray userEncode(const QString &userNick, const QString &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.value(channel.toLower(), 0); }
-
-public slots:
- // void setServerOptions();
- void connectToIrc(bool reconnecting = false);
- void disconnectFromIrc(bool requested = true, const QString &reason = QString());
- void userInput(BufferInfo bufferInfo, QString msg);
-
- void putRawLine(QByteArray input);
- int lastParamOverrun(const QString &cmd, const QList<QByteArray> ¶ms);
- void putCmd(const QString &cmd, const QList<QByteArray> ¶ms, const QByteArray &prefix = QByteArray());
-
- void setChannelJoined(const QString &channel);
- void setChannelParted(const QString &channel);
- void addChannelKey(const QString &channel, const QString &key);
- void removeChannelKey(const QString &channel);
-
- bool setAutoWhoDone(const QString &channel);
-
-signals:
- // #void networkState(QString net, QVariantMap data);
- void recvRawServerMsg(QString);
- void displayStatusMsg(QString);
- //void displayMsg(Message msg);
- void displayMsg(Message::Type, BufferInfo::Type, QString target, QString text, QString sender = "", Message::Flags flags = Message::None);
- void connected(NetworkId networkId); ///< Emitted after receipt of 001 to indicate that we can now send data to the IRC server
- void disconnected(NetworkId networkId);
- void connectionStateChanged(Network::ConnectionState);
- void connectionInitialized(); ///< Emitted after receipt of 001 to indicate that we can now send data to the IRC server
- void connectionError(const QString &errorMsg);
-
- void quitRequested(NetworkId networkId);
-
- //void queryRequested(QString network, QString nick);
- void nickChanged(const NetworkId &networkId, const QString &newNick, const QString &oldNick); // this signal is inteded to rename query buffers in the storage backend
- void channelJoined(NetworkId, const QString &channel, const QString &key = QString());
- void channelParted(NetworkId, const QString &channel);
-
- void sslErrors(const QVariant &errorData);
-
-private slots:
- void socketHasData();
- void socketError(QAbstractSocket::SocketError);
- void socketConnected();
- void socketInitialized();
- void socketCloseTimeout();
- void socketDisconnected();
- void socketStateChanged(QAbstractSocket::SocketState);
- void setConnectionState(Network::ConnectionState);
- void networkInitialized(const QString ¤tServer);
-
- void sendPerform();
- void autoReconnectSettingsChanged();
- void doAutoReconnect();
- void sendPing();
- void sendAutoWho();
- void startAutoWhoCycle();
- void nickChanged(const QString &newNick, const QString &oldNick); // this signal is inteded to rename query buffers in the storage backend
-
-#ifdef HAVE_SSL
- void socketEncrypted();
- void sslErrors(const QList<QSslError> &errors);
-#endif
-
- void fillBucketAndProcessQueue();
-
-private:
-#ifdef HAVE_SSL
- QSslSocket socket;
-#else
- QTcpSocket socket;
-#endif
-
- Network::ConnectionState _connectionState;
-
- Network *_network;
- CoreSession *_coreSession;
- BufferInfo _statusBufferInfo;
-
- IrcServerHandler *_ircServerHandler;
- UserInputHandler *_userInputHandler;
- CtcpHandler *_ctcpHandler;
-
- QHash<QString, QString> _channelKeys; // stores persistent channels and their passwords, if any
-
- QTimer _autoReconnectTimer;
-
- int _autoReconnectCount;
-
- QTimer _socketCloseTimer;
-
- /* this flag triggers quitRequested() once the socket is closed
- * it is needed to determine whether or not the connection needs to be
- *in the automatic session restore. */
- bool _quitRequested;
-
- bool _previousConnectionAttemptFailed;
- int _lastUsedServerlistIndex;
-
- QTimer _pingTimer;
-
- bool _autoWhoEnabled;
- QStringList _autoWhoQueue;
- QHash<QString, int> _autoWhoInProgress;
- int _autoWhoInterval;
- int _autoWhoNickLimit;
- int _autoWhoDelay;
- QTimer _autoWhoTimer, _autoWhoCycleTimer;
-
- QTimer _tokenBucketTimer;
- int _messagesPerSecond; // token refill speed
- int _burstSize; // size of the token bucket
- int _tokenBucket; // the virtual bucket that holds the tokens
- QList<QByteArray> _msgQueue;
-
- void writeToSocket(QByteArray s);
-
- class ParseError : public Exception {
- public:
- ParseError(QString cmd, QString prefix, QStringList params);
- };
-
- class UnknownCmdError : public Exception {
- public:
- UnknownCmdError(QString cmd, QString prefix, QStringList params);
- };
-};
-
-#endif
#include "util.h"
-#include "networkconnection.h"
-#include "network.h"
#include "ctcphandler.h"
+#include "identity.h"
#include "ircuser.h"
#include <QDebug>
#include <QRegExp>
-UserInputHandler::UserInputHandler(NetworkConnection *parent) : BasicHandler(parent) {
+UserInputHandler::UserInputHandler(CoreNetwork *parent)
+ : BasicHandler(parent)
+{
}
void UserInputHandler::handleUserInput(const BufferInfo &bufferInfo, const QString &msg_) {
// ====================
// Public Slots
// ====================
-
void UserInputHandler::handleAway(const BufferInfo &bufferInfo, const QString &msg) {
Q_UNUSED(bufferInfo)
// if there is no message supplied we have to check if we are already away or not
if(msg.isEmpty()) {
if(me && !me->isAway())
- awayMsg = networkConnection()->identity()->awayReason();
+ awayMsg = network()->identityPtr()->awayReason();
}
if(me)
me->setAwayMessage(awayMsg);
void UserInputHandler::handleCtcp(const BufferInfo &bufferInfo, const QString &msg) {
Q_UNUSED(bufferInfo)
+
QString nick = msg.section(' ', 0, 0);
QString ctcpTag = msg.section(' ', 1, 1).toUpper();
- if (ctcpTag.isEmpty()) return;
+ if(ctcpTag.isEmpty())
+ return;
+
QString message = "";
QString verboseMessage = tr("sending CTCP-%1 request").arg(ctcpTag);
message = QString::number(now);
}
- networkConnection()->ctcpHandler()->query(nick, ctcpTag, message);
+ network()->ctcpHandler()->query(nick, ctcpTag, message);
emit displayMsg(Message::Action, BufferInfo::StatusBuffer, "", verboseMessage, network()->myNick());
}
i = 0;
for(; i < keys.count(); i++) {
if(i >= chans.count()) break;
- networkConnection()->addChannelKey(chans[i], keys[i]);
+ network()->addChannelKey(chans[i], keys[i]);
}
for(; i < chans.count(); i++) {
- networkConnection()->removeChannelKey(chans[i]);
+ network()->removeChannelKey(chans[i]);
}
}
QString nick = msg.section(' ', 0, 0, QString::SectionSkipEmpty);
QString reason = msg.section(' ', 1, -1, QString::SectionSkipEmpty).trimmed();
if(reason.isEmpty())
- reason = networkConnection()->identity()->kickReason();
+ reason = network()->identityPtr()->kickReason();
QList<QByteArray> params;
params << serverEncode(bufferInfo.bufferName()) << serverEncode(nick) << channelEncode(bufferInfo.bufferName(), reason);
void UserInputHandler::handleMe(const BufferInfo &bufferInfo, const QString &msg) {
if(bufferInfo.bufferName().isEmpty()) return; // server buffer
- networkConnection()->ctcpHandler()->query(bufferInfo.bufferName(), "ACTION", msg);
+ network()->ctcpHandler()->query(bufferInfo.bufferName(), "ACTION", msg);
emit displayMsg(Message::Action, bufferInfo.type(), bufferInfo.bufferName(), msg, network()->myNick(), Message::Self);
}
if(!msg.contains(' '))
return;
- QList<QByteArray> params;
- params << serverEncode(msg.section(' ', 0, 0));
- params << userEncode(params[0], msg.section(' ', 1));
-
- emit putCmd("PRIVMSG", params);
+ QByteArray target = serverEncode(msg.section(' ', 0, 0));
+ putPrivmsg(target, userEncode(target, msg.section(' ', 1)));
}
void UserInputHandler::handleNick(const BufferInfo &bufferInfo, const QString &msg) {
}
if(partReason.isEmpty())
- partReason = networkConnection()->identity()->partReason();
+ partReason = network()->identityPtr()->partReason();
params << serverEncode(channelName) << channelEncode(bufferInfo.bufferName(), partReason);
emit putCmd("PART", params);
void UserInputHandler::handleQuit(const BufferInfo &bufferInfo, const QString &msg) {
Q_UNUSED(bufferInfo)
- networkConnection()->disconnectFromIrc(true, msg);
+ network()->disconnectFromIrc(true, msg);
}
void UserInputHandler::issueQuit(const QString &reason) {
QString quitReason;
if(reason.isEmpty())
- quitReason = networkConnection()->identity()->quitReason();
+ quitReason = network()->identityPtr()->quitReason();
else
quitReason = reason;
emit putCmd("QUIT", serverEncode(quitReason));
}
void UserInputHandler::handleSay(const BufferInfo &bufferInfo, const QString &msg) {
- if(bufferInfo.bufferName().isEmpty()) return; // server buffer
- QList<QByteArray> params;
- params << serverEncode(bufferInfo.bufferName()) << channelEncode(bufferInfo.bufferName(), msg);
- emit putCmd("PRIVMSG", params);
+ if(bufferInfo.bufferName().isEmpty())
+ return; // server buffer
+ putPrivmsg(serverEncode(bufferInfo.bufferName()), channelEncode(bufferInfo.bufferName(), msg));
emit displayMsg(Message::Plain, bufferInfo.type(), bufferInfo.bufferName(), msg, network()->myNick(), Message::Self);
}
}
+void UserInputHandler::putPrivmsg(const QByteArray &target, const QByteArray &message) {
+ static const char *cmd = "PRIVMSG";
+ int overrun = lastParamOverrun(cmd, QList<QByteArray>() << message);
+ if(overrun) {
+ static const char *splitter = " .,-";
+ int maxSplitPos = message.count() - overrun;
+ int splitPos = -1;
+ for(const char *splitChar = splitter; *splitChar != 0; splitChar++) {
+ splitPos = qMax(splitPos, message.lastIndexOf(*splitChar, maxSplitPos));
+ }
+ if(splitPos <= 0) {
+ splitPos = maxSplitPos;
+ }
+ putCmd(cmd, QList<QByteArray>() << target << message.left(splitPos));
+ putPrivmsg(target, message.mid(splitPos));
+ return;
+ } else {
+ putCmd(cmd, QList<QByteArray>() << target << message);
+ }
+}
+
+// returns 0 if the message will not be chopped by the irc server or number of chopped bytes if message is too long
+int UserInputHandler::lastParamOverrun(const QString &cmd, const QList<QByteArray> ¶ms) {
+ // the server will pass our message trunkated to 512 bytes including CRLF with the following format:
+ // ":prefix COMMAND param0 param1 :lastparam"
+ // where prefix = "nickname!user@host"
+ // that means that the last message can be as long as:
+ // 512 - nicklen - userlen - hostlen - commandlen - sum(param[0]..param[n-1])) - 2 (for CRLF) - 4 (":!@" + 1space between prefix and command) - max(paramcount - 1, 0) (space for simple params) - 2 (space and colon for last param)
+ IrcUser *me = network()->me();
+ int maxLen = 480 - cmd.toAscii().count(); // educated guess in case we don't know us (yet?)
+
+ if(me)
+ maxLen = 512 - serverEncode(me->nick()).count() - serverEncode(me->user()).count() - serverEncode(me->host()).count() - cmd.toAscii().count() - 6;
+
+ if(!params.isEmpty()) {
+ for(int i = 0; i < params.count() - 1; i++) {
+ maxLen -= (params[i].count() + 1);
+ }
+ maxLen -= 2; // " :" last param separator;
+
+ if(params.last().count() > maxLen) {
+ return params.last().count() - maxLen;
+ } else {
+ return 0;
+ }
+ } else {
+ return 0;
+ }
+}
Q_OBJECT
public:
- UserInputHandler(NetworkConnection *parent = 0);
+ UserInputHandler(CoreNetwork *parent = 0);
void handleUserInput(const BufferInfo &bufferInfo, const QString &text);
private:
void expand(const QString &alias, const BufferInfo &bufferInfo, const QString &msg);
void banOrUnban(const BufferInfo &bufferInfo, const QString &text, bool ban);
+ void putPrivmsg(const QByteArray &target, const QByteArray &message);
+ int lastParamOverrun(const QString &cmd, const QList<QByteArray> ¶ms);
};