From 68eca2c9f0ae5acbda19a6965a2630bd4649ef24 Mon Sep 17 00:00:00 2001 From: Manuel Nickschas Date: Wed, 13 Oct 2010 22:50:44 +0200 Subject: [PATCH] Event backend porting Port netsplit handling from IrcServerHandler to CoreSessionEventProcessor, and port related commands: JOIN, QUIT, MODE, RPL_CHANNELMODEIS (324) --- src/common/event.h | 1 + src/common/eventmanager.h | 10 +- src/common/networkevent.h | 25 +++ src/core/coresession.cpp | 1 + src/core/coresessioneventprocessor.cpp | 276 ++++++++++++++++++++++++- src/core/coresessioneventprocessor.h | 51 ++++- src/core/eventstringifier.cpp | 48 +++++ src/core/eventstringifier.h | 8 + src/core/ircserverhandler.cpp | 260 +---------------------- src/core/ircserverhandler.h | 35 ---- src/core/netsplit.cpp | 14 +- src/core/netsplit.h | 20 +- 12 files changed, 436 insertions(+), 313 deletions(-) diff --git a/src/common/event.h b/src/common/event.h index 4e4abacf..acca4110 100644 --- a/src/common/event.h +++ b/src/common/event.h @@ -36,6 +36,7 @@ public: inline void setFlag(EventManager::EventFlag flag) { _flags |= flag; } inline void setFlags(EventManager::EventFlags flags) { _flags = flags; } + inline bool testFlag(EventManager::EventFlag flag) { return _flags.testFlag(flag); } inline EventManager::EventFlags flags() const { return _flags; } inline void stop() { setFlag(EventManager::Stopped); } diff --git a/src/common/eventmanager.h b/src/common/eventmanager.h index 4030cffa..d4f49c75 100644 --- a/src/common/eventmanager.h +++ b/src/common/eventmanager.h @@ -46,9 +46,11 @@ public: }; enum EventFlag { - Backlog = 0x20, - Silent = 0x40, ///< Don't generate a MessageEvent - Stopped = 0x80 + Fake = 0x08, ///< Ignore this in CoreSessionEventProcessor + Netsplit = 0x10, ///< Netsplit join/part, ignore on display + Backlog = 0x20, + Silent = 0x40, ///< Don't generate a MessageEvent + Stopped = 0x80 }; Q_DECLARE_FLAGS(EventFlags, EventFlag) @@ -71,6 +73,8 @@ public: NetworkReconnecting, NetworkDisconnecting, NetworkDisconnected, + NetworkSplitJoin, + NetworkSplitQuit, NetworkIncoming, IrcServerEvent = 0x00020000, diff --git a/src/common/networkevent.h b/src/common/networkevent.h index 67b47a0f..a1d3a667 100644 --- a/src/common/networkevent.h +++ b/src/common/networkevent.h @@ -90,4 +90,29 @@ private: QByteArray _data; }; +class NetworkSplitEvent : public NetworkEvent { + +public: + explicit NetworkSplitEvent(EventManager::EventType type, + Network *network, + const QString &channel, + const QStringList &users, + const QString &quitMsg) + : NetworkEvent(type, network), + _channel(channel), + _users(users), + _quitMsg(quitMsg) + {} + + inline QString channel() const { return _channel; } + inline QStringList users() const { return _users; } + inline QString quitMessage() const { return _quitMsg; } + +private: + QString _channel; + QStringList _users; + QString _quitMsg; +}; + + #endif diff --git a/src/core/coresession.cpp b/src/core/coresession.cpp index 8d2c8773..0ea6dec0 100644 --- a/src/core/coresession.cpp +++ b/src/core/coresession.cpp @@ -100,6 +100,7 @@ CoreSession::CoreSession(UserId uid, bool restoreState, QObject *parent) eventManager()->registerObject(eventProcessor(), EventManager::HighPriority); // needs to process events *before* the stringifier! eventManager()->registerObject(eventStringifier(), EventManager::NormalPriority); eventManager()->registerObject(this, EventManager::LowPriority); // for sending MessageEvents to the client + eventManager()->registerObject(eventProcessor(), EventManager::LowPriority, "lateProcess"); // some events need to be handled after msg generation // periodically save our session state connect(&(Core::instance()->syncTimer()), SIGNAL(timeout()), this, SLOT(saveSessionState())); diff --git a/src/core/coresessioneventprocessor.cpp b/src/core/coresessioneventprocessor.cpp index cb116919..bb2c211b 100644 --- a/src/core/coresessioneventprocessor.cpp +++ b/src/core/coresessioneventprocessor.cpp @@ -26,12 +26,13 @@ #include "ircevent.h" #include "ircuser.h" #include "messageevent.h" +#include "netsplit.h" CoreSessionEventProcessor::CoreSessionEventProcessor(CoreSession *session) : QObject(session), _coreSession(session) { - + connect(coreSession(), SIGNAL(networkDisconnected(NetworkId)), this, SLOT(destroyNetsplits(NetworkId))); } bool CoreSessionEventProcessor::checkParamCount(IrcEvent *e, int minParams) { @@ -122,6 +123,36 @@ void CoreSessionEventProcessor::processIrcEventInvite(IrcEvent *e) { } } +void CoreSessionEventProcessor::processIrcEventJoin(IrcEvent *e) { + if(e->testFlag(EventManager::Fake)) // generated by handleEarlyNetsplitJoin + return; + + if(!checkParamCount(e, 1)) + return; + + CoreNetwork *net = coreNetwork(e); + QString channel = e->params()[0]; + IrcUser *ircuser = net->updateNickFromMask(e->prefix()); + + bool handledByNetsplit = false; + foreach(Netsplit* n, _netsplits.value(e->network())) { + handledByNetsplit = n->userJoined(e->prefix(), channel); + if(handledByNetsplit) + break; + } + + if(!handledByNetsplit) + ircuser->joinChannel(channel); + else + e->setFlag(EventManager::Netsplit); + + if(net->isMe(ircuser)) { + net->setChannelJoined(channel); + // FIXME use event + net->putRawLine(net->serverEncode("MODE " + channel)); // we want to know the modes of the channel we just joined, so we ask politely + } +} + void CoreSessionEventProcessor::processIrcEventKick(IrcEvent *e) { if(checkParamCount(e, 2)) { e->network()->updateNickFromMask(e->prefix()); @@ -133,6 +164,112 @@ void CoreSessionEventProcessor::processIrcEventKick(IrcEvent *e) { } } +void CoreSessionEventProcessor::processIrcEventMode(IrcEvent *e) { + if(!checkParamCount(e, 2)) + return; + + if(e->network()->isChannelName(e->params().first())) { + // Channel Modes + + IrcChannel *channel = e->network()->ircChannel(e->params()[0]); + if(!channel) { + // we received mode information for a channel we're not in. that means probably we've just been kicked out or something like that + // anyways: we don't have a place to store the data --> discard the info. + return; + } + + QString modes = e->params()[1]; + bool add = true; + int paramOffset = 2; + for(int c = 0; c < modes.length(); c++) { + if(modes[c] == '+') { + add = true; + continue; + } + if(modes[c] == '-') { + add = false; + continue; + } + + if(e->network()->prefixModes().contains(modes[c])) { + // user channel modes (op, voice, etc...) + if(paramOffset < e->params().count()) { + IrcUser *ircUser = e->network()->ircUser(e->params()[paramOffset]); + if(!ircUser) { + qWarning() << Q_FUNC_INFO << "Unknown IrcUser:" << e->params()[paramOffset]; + } else { + if(add) { + bool handledByNetsplit = false; + QHash splits = _netsplits.value(e->network()); + foreach(Netsplit* n, _netsplits.value(e->network())) { + handledByNetsplit = n->userAlreadyJoined(ircUser->hostmask(), channel->name()); + if(handledByNetsplit) { + n->addMode(ircUser->hostmask(), channel->name(), QString(modes[c])); + break; + } + } + if(!handledByNetsplit) + channel->addUserMode(ircUser, QString(modes[c])); + } + else + channel->removeUserMode(ircUser, QString(modes[c])); + } + } else { + qWarning() << "Received MODE with too few parameters:" << e->params(); + } + ++paramOffset; + } else { + // regular channel modes + QString value; + Network::ChannelModeType modeType = e->network()->channelModeType(modes[c]); + if(modeType == Network::A_CHANMODE || modeType == Network::B_CHANMODE || (modeType == Network::C_CHANMODE && add)) { + if(paramOffset < e->params().count()) { + value = e->params()[paramOffset]; + } else { + qWarning() << "Received MODE with too few parameters:" << e->params(); + } + ++paramOffset; + } + + if(add) + channel->addChannelMode(modes[c], value); + else + channel->removeChannelMode(modes[c], value); + } + } + + } else { + // pure User Modes + IrcUser *ircUser = e->network()->newIrcUser(e->params().first()); + QString modeString(e->params()[1]); + QString addModes; + QString removeModes; + bool add = false; + for(int c = 0; c < modeString.count(); c++) { + if(modeString[c] == '+') { + add = true; + continue; + } + if(modeString[c] == '-') { + add = false; + continue; + } + if(add) + addModes += modeString[c]; + else + removeModes += modeString[c]; + } + if(!addModes.isEmpty()) + ircUser->addUserModes(addModes); + if(!removeModes.isEmpty()) + ircUser->removeUserModes(removeModes); + + if(e->network()->isMe(ircUser)) { + coreNetwork(e)->updatePersistentModes(addModes, removeModes); + } + } +} + void CoreSessionEventProcessor::processIrcEventNick(IrcEvent *e) { if(checkParamCount(e, 1)) { IrcUser *ircuser = e->network()->updateNickFromMask(e->prefix()); @@ -176,6 +313,50 @@ void CoreSessionEventProcessor::processIrcEventPong(IrcEvent *e) { } } +void CoreSessionEventProcessor::processIrcEventQuit(IrcEvent *e) { + IrcUser *ircuser = e->network()->updateNickFromMask(e->prefix()); + if(!ircuser) + return; + + QString msg; + if(e->params().count() > 0) + msg = e->params()[0]; + + // check if netsplit + if(Netsplit::isNetsplit(msg)) { + Netsplit *n; + if(!_netsplits[e->network()].contains(msg)) { + n = new Netsplit(e->network(), this); + connect(n, SIGNAL(finished()), this, SLOT(handleNetsplitFinished())); + connect(n, SIGNAL(netsplitJoin(Network*,QString,QStringList,QStringList,QString)), + this, SLOT(handleNetsplitJoin(Network*,QString,QStringList,QStringList,QString))); + connect(n, SIGNAL(netsplitQuit(Network*,QString,QStringList,QString)), + this, SLOT(handleNetsplitQuit(Network*,QString,QStringList,QString))); + connect(n, SIGNAL(earlyJoin(Network*,QString,QStringList,QStringList)), + this, SLOT(handleEarlyNetsplitJoin(Network*,QString,QStringList,QStringList))); + _netsplits[e->network()].insert(msg, n); + } + else { + n = _netsplits[e->network()][msg]; + } + // add this user to the netsplit + n->userQuit(e->prefix(), ircuser->channels(), msg); + e->setFlag(EventManager::Netsplit); + } + // normal quit is handled in lateProcessIrcEventQuit() +} + +void CoreSessionEventProcessor::lateProcessIrcEventQuit(IrcEvent *e) { + if(e->testFlag(EventManager::Netsplit)) + return; + + IrcUser *ircuser = e->network()->updateNickFromMask(e->prefix()); + if(!ircuser) + return; + + ircuser->quit(); +} + void CoreSessionEventProcessor::processIrcEventTopic(IrcEvent *e) { if(checkParamCount(e, 2)) { e->network()->updateNickFromMask(e->prefix()); @@ -393,6 +574,11 @@ void CoreSessionEventProcessor::processIrcEvent323(IrcEvent *e) { e->stop(); // consumed by IrcListHelper, so don't further process/show this event } +/* RPL_CHANNELMODEIS - " " */ +void CoreSessionEventProcessor::processIrcEvent324(IrcEvent *e) { + processIrcEventMode(e); +} + /* RPL_NOTOPIC */ void CoreSessionEventProcessor::processIrcEvent331(IrcEvent *e) { if(!checkParamCount(e, 1)) @@ -524,3 +710,91 @@ void CoreSessionEventProcessor::processIrcEvent(IrcEvent *e) { } */ +/* Handle signals from Netsplit objects */ + +void CoreSessionEventProcessor::handleNetsplitJoin(Network *net, + const QString &channel, + const QStringList &users, + const QStringList &modes, + const QString& quitMessage) +{ + IrcChannel *ircChannel = net->ircChannel(channel); + if(!ircChannel) { + return; + } + QList ircUsers; + QStringList newModes = modes; + QStringList newUsers = users; + + foreach(const QString &user, users) { + IrcUser *iu = net->ircUser(nickFromMask(user)); + if(iu) + ircUsers.append(iu); + else { // the user already quit + int idx = users.indexOf(user); + newUsers.removeAt(idx); + newModes.removeAt(idx); + } + } + + ircChannel->joinIrcUsers(ircUsers, newModes); + NetworkSplitEvent *event = new NetworkSplitEvent(EventManager::NetworkSplitJoin, net, channel, newUsers, quitMessage); + coreSession()->eventManager()->sendEvent(event); +} + +void CoreSessionEventProcessor::handleNetsplitQuit(Network *net, const QString &channel, const QStringList &users, const QString& quitMessage) { + NetworkSplitEvent *event = new NetworkSplitEvent(EventManager::NetworkSplitQuit, net, channel, users, quitMessage); + coreSession()->eventManager()->sendEvent(event); + foreach(QString user, users) { + IrcUser *iu = net->ircUser(nickFromMask(user)); + if(iu) + iu->quit(); + } +} + +void CoreSessionEventProcessor::handleEarlyNetsplitJoin(Network *net, const QString &channel, const QStringList &users, const QStringList &modes) { + IrcChannel *ircChannel = net->ircChannel(channel); + if(!ircChannel) { + qDebug() << "handleEarlyNetsplitJoin(): channel " << channel << " invalid"; + return; + } + QList events; + QList ircUsers; + QStringList newModes = modes; + + foreach(QString user, users) { + IrcUser *iu = net->updateNickFromMask(user); + if(iu) { + ircUsers.append(iu); + // fake event for scripts that consume join events + events << new IrcEvent(EventManager::IrcEventJoin, net, iu->hostmask(), QStringList() << channel); + } + else { + newModes.removeAt(users.indexOf(user)); + } + } + ircChannel->joinIrcUsers(ircUsers, newModes); + foreach(NetworkEvent *event, events) { + event->setFlag(EventManager::Fake); // ignore this in here! + coreSession()->eventManager()->sendEvent(event); + } +} + +void CoreSessionEventProcessor::handleNetsplitFinished() { + Netsplit* n = qobject_cast(sender()); + Q_ASSERT(n); + QHash splithash = _netsplits.take(n->network()); + splithash.remove(splithash.key(n)); + if(splithash.count()) + _netsplits[n->network()] = splithash; + n->deleteLater(); +} + +void CoreSessionEventProcessor::destroyNetsplits(NetworkId netId) { + Network *net = coreSession()->network(netId); + if(!net) + return; + + QHash splits = _netsplits.take(net); + qDeleteAll(splits); +} diff --git a/src/core/coresessioneventprocessor.h b/src/core/coresessioneventprocessor.h index 59b48793..258dc44b 100644 --- a/src/core/coresessioneventprocessor.h +++ b/src/core/coresessioneventprocessor.h @@ -27,6 +27,7 @@ class CoreSession; class IrcEvent; class IrcEventNumeric; +class Netsplit; class CoreSessionEventProcessor : public QObject { Q_OBJECT @@ -41,10 +42,14 @@ public: Q_INVOKABLE void processIrcEventAuthenticate(IrcEvent *event); // SASL auth Q_INVOKABLE void processIrcEventCap(IrcEvent *event); // CAP framework Q_INVOKABLE void processIrcEventInvite(IrcEvent *event); + Q_INVOKABLE void processIrcEventJoin(IrcEvent *event); Q_INVOKABLE void processIrcEventKick(IrcEvent *event); + Q_INVOKABLE void processIrcEventMode(IrcEvent *event); Q_INVOKABLE void processIrcEventNick(IrcEvent *event); Q_INVOKABLE void processIrcEventPart(IrcEvent *event); Q_INVOKABLE void processIrcEventPong(IrcEvent *event); + Q_INVOKABLE void processIrcEventQuit(IrcEvent *event); + Q_INVOKABLE void lateProcessIrcEventQuit(IrcEvent *event); Q_INVOKABLE void processIrcEventTopic(IrcEvent *event); Q_INVOKABLE void processIrcEvent001(IrcEvent *event); // RPL_WELCOME @@ -65,13 +70,14 @@ public: Q_INVOKABLE void processIrcEvent317(IrcEvent *event); // RPL_WHOISIDLE Q_INVOKABLE void processIrcEvent322(IrcEvent *event); // RPL_LIST Q_INVOKABLE void processIrcEvent323(IrcEvent *event); // RPL_LISTEND + Q_INVOKABLE void processIrcEvent324(IrcEvent *event); // RPL_CHANNELMODEIS Q_INVOKABLE void processIrcEvent331(IrcEvent *event); // RPL_NOTOPIC Q_INVOKABLE void processIrcEvent332(IrcEvent *event); // RPL_TOPIC Q_INVOKABLE void processIrcEvent352(IrcEvent *event); // RPL_WHOREPLY Q_INVOKABLE void processIrcEvent353(IrcEvent *event); // RPL_NAMREPLY - Q_INVOKABLE void processIrcEvent432(IrcEventNumeric *event); // ERR_ERRONEUSNICKNAME - Q_INVOKABLE void processIrcEvent433(IrcEventNumeric *event); // ERR_NICKNAMEINUSE - Q_INVOKABLE void processIrcEvent437(IrcEventNumeric *event); // ERR_UNAVAILRESOURCE + Q_INVOKABLE void processIrcEvent432(IrcEventNumeric *event); // ERR_ERRONEUSNICKNAME + Q_INVOKABLE void processIrcEvent433(IrcEventNumeric *event); // ERR_NICKNAMEINUSE + Q_INVOKABLE void processIrcEvent437(IrcEventNumeric *event); // ERR_UNAVAILRESOURCE // Q_INVOKABLE void processIrcEvent(IrcEvent *event); @@ -80,8 +86,47 @@ protected: inline CoreNetwork *coreNetwork(NetworkEvent *e) const { return qobject_cast(e->network()); } void tryNextNick(NetworkEvent *e, const QString &errnick, bool erroneous = false); +private slots: + //! Joins after a netsplit + /** This slot handles a bulk-join after a netsplit is over + * \param net The network + * \param channel The channel the users joined + * \param users The list of users that joind the channel + * \param modes The list of modes the users get set + * \param quitMessage The message we received when the netsplit occured + */ + void handleNetsplitJoin(Network *net, const QString &channel, const QStringList &users, const QStringList &modes, const QString &quitMessage); + + //! Quits after a netsplit + /** This slot handles a bulk-quit after a netsplit occured + * \param net The network + * \param channel The channel the users quitted + * \param users The list of users that got split + * \param quitMessage The message we received when the netsplit occured + */ + void handleNetsplitQuit(Network *net, const QString &channel, const QStringList &users, const QString &quitMessage); + + //! Netsplit finished + /** This slot deletes the netsplit object that sent the finished() signal + */ + void handleNetsplitFinished(); + + void handleEarlyNetsplitJoin(Network *net, const QString &channel, const QStringList &users, const QStringList &modes); + + //! Destroy any existing netsplits + /** This slot deletes all netsplit objects + * Used to get rid of existing netsplits on network reconnect + * \param network The network we want to clear + */ + void destroyNetsplits(NetworkId network); + private: CoreSession *_coreSession; + + // structure to organize netsplits + // key: quit message + // value: the corresponding netsplit object + QHash > _netsplits; }; #endif diff --git a/src/core/eventstringifier.cpp b/src/core/eventstringifier.cpp index a7238b27..1578f78e 100644 --- a/src/core/eventstringifier.cpp +++ b/src/core/eventstringifier.cpp @@ -64,6 +64,19 @@ bool EventStringifier::checkParamCount(IrcEvent *e, int minParams) { return true; } +/* These are only for legacy reasons; remove as soon as we handle NetworkSplitEvents properly */ +void EventStringifier::processNetworkSplitJoin(NetworkSplitEvent *e) { + QString msg = e->users().join("#:#") + "#:#" + e->quitMessage(); + displayMsg(e, Message::NetsplitJoin, msg, QString(), e->channel()); +} + +void EventStringifier::processNetworkSplitQuit(NetworkSplitEvent *e) { + QString msg = e->users().join("#:#") + "#:#" + e->quitMessage(); + displayMsg(e, Message::NetsplitQuit, msg, QString(), e->channel()); +} + +/* End legacy */ + void EventStringifier::processIrcEventNumeric(IrcEventNumeric *e) { //qDebug() << e->number(); switch(e->number()) { @@ -134,6 +147,13 @@ void EventStringifier::processIrcEventInvite(IrcEvent *e) { displayMsg(e, Message::Invite, tr("%1 invited you to channel %2").arg(e->nick(), e->params().at(1))); } +void EventStringifier::processIrcEventJoin(IrcEvent *e) { + if(e->testFlag(EventManager::Netsplit)) + return; + + displayMsg(e, Message::Join, e->params()[0], e->prefix(), e->params()[0]); +} + void EventStringifier::earlyProcessIrcEventKick(IrcEvent *e) { IrcUser *victim = e->network()->ircUser(e->params().at(1)); if(victim) { @@ -146,6 +166,17 @@ void EventStringifier::earlyProcessIrcEventKick(IrcEvent *e) { } } +void EventStringifier::processIrcEventMode(IrcEvent *e) { + if(e->network()->isChannelName(e->params().first())) { + // Channel Modes + displayMsg(e, Message::Mode, e->params().join(" "), e->prefix(), e->params().first()); + } else { + // User Modes + // FIXME: redirect + displayMsg(e, Message::Mode, e->params().join(" "), e->prefix()); + } +} + // this needs to be called before the ircuser is renamed! void EventStringifier::earlyProcessIrcEventNick(IrcEvent *e) { if(!checkParamCount(e, 1)) @@ -182,6 +213,18 @@ void EventStringifier::processIrcEventPong(IrcEvent *e) { displayMsg(e, Message::Server, "PONG " + e->params().join(" "), e->prefix()); } +void EventStringifier::processIrcEventQuit(IrcEvent *e) { + if(e->testFlag(EventManager::Netsplit)) + return; + + IrcUser *ircuser = e->network()->updateNickFromMask(e->prefix()); + if(!ircuser) + return; + + foreach(const QString &channel, ircuser->channels()) + displayMsg(e, Message::Quit, e->params().count()? e->params().first() : QString(), e->prefix(), channel); +} + void EventStringifier::processIrcEventTopic(IrcEvent *e) { displayMsg(e, Message::Topic, tr("%1 has changed topic for %2 to: \"%3\"") .arg(e->nick(), e->params().at(0), e->params().at(1)), QString(), e->params().at(0)); @@ -350,6 +393,11 @@ void EventStringifier::processIrcEvent323(IrcEvent *e) { displayMsg(e, Message::Server, tr("End of channel list")); } +/* RPL_CHANNELMODEIS - " " */ +void EventStringifier::processIrcEvent324(IrcEvent *e) { + processIrcEventMode(e); +} + /* RPL_??? - " */ void EventStringifier::processIrcEvent328(IrcEvent *e) { if(!checkParamCount(e, 2)) diff --git a/src/core/eventstringifier.h b/src/core/eventstringifier.h index 25733ad4..eeecac91 100644 --- a/src/core/eventstringifier.h +++ b/src/core/eventstringifier.h @@ -47,14 +47,21 @@ public: const QString &target = QString(), Message::Flags msgFlags = Message::None); + // legacy handlers + Q_INVOKABLE void processNetworkSplitJoin(NetworkSplitEvent *event); + Q_INVOKABLE void processNetworkSplitQuit(NetworkSplitEvent *event); + //! Handle generic numeric events Q_INVOKABLE void processIrcEventNumeric(IrcEventNumeric *event); Q_INVOKABLE void processIrcEventInvite(IrcEvent *event); + Q_INVOKABLE void processIrcEventJoin(IrcEvent *event); Q_INVOKABLE void earlyProcessIrcEventKick(IrcEvent *event); + Q_INVOKABLE void processIrcEventMode(IrcEvent *event); Q_INVOKABLE void earlyProcessIrcEventNick(IrcEvent *event); Q_INVOKABLE void earlyProcessIrcEventPart(IrcEvent *event); Q_INVOKABLE void processIrcEventPong(IrcEvent *event); + Q_INVOKABLE void processIrcEventQuit(IrcEvent *event); Q_INVOKABLE void processIrcEventTopic(IrcEvent *event); Q_INVOKABLE void processIrcEvent005(IrcEvent *event); // RPL_ISUPPORT @@ -70,6 +77,7 @@ public: Q_INVOKABLE void processIrcEvent319(IrcEvent *event); // RPL_WHOISCHANNELS Q_INVOKABLE void processIrcEvent322(IrcEvent *event); // RPL_LIST Q_INVOKABLE void processIrcEvent323(IrcEvent *event); // RPL_LISTEND + Q_INVOKABLE void processIrcEvent324(IrcEvent *event); // RPL_CHANNELMODEIS Q_INVOKABLE void processIrcEvent328(IrcEvent *event); // RPL_??? (channel creation time) Q_INVOKABLE void processIrcEvent329(IrcEvent *event); // RPL_??? (channel homepage) Q_INVOKABLE void processIrcEvent330(IrcEvent *event); // RPL_WHOISACCOUNT (quakenet/snircd/undernet) diff --git a/src/core/ircserverhandler.cpp b/src/core/ircserverhandler.cpp index ae7c42b4..36381294 100644 --- a/src/core/ircserverhandler.cpp +++ b/src/core/ircserverhandler.cpp @@ -40,11 +40,11 @@ IrcServerHandler::IrcServerHandler(CoreNetwork *parent) : CoreBasicHandler(parent), _whois(false) { - connect(parent, SIGNAL(disconnected(NetworkId)), this, SLOT(destroyNetsplits())); + } IrcServerHandler::~IrcServerHandler() { - destroyNetsplits(); + } /*! Handle a raw message string sent by the server. We try to find a suitable handler, otherwise we call a default handler. */ @@ -140,146 +140,6 @@ void IrcServerHandler::defaultHandler(QString cmd, const QString &prefix, const // IRC SERVER HANDLER //******************************/ -void IrcServerHandler::handleJoin(const QString &prefix, const QList ¶ms) { - if(!checkParamCount("IrcServerHandler::handleJoin()", params, 1)) - return; - - QString channel = serverDecode(params[0]); - IrcUser *ircuser = network()->updateNickFromMask(prefix); - - bool handledByNetsplit = false; - if(!_netsplits.empty()) { - foreach(Netsplit* n, _netsplits) { - handledByNetsplit = n->userJoined(prefix, channel); - if(handledByNetsplit) - break; - } - } - - // normal join - if(!handledByNetsplit) { - emit displayMsg(Message::Join, BufferInfo::ChannelBuffer, channel, channel, prefix); - ircuser->joinChannel(channel); - } - //qDebug() << "IrcServerHandler::handleJoin()" << prefix << params; - - if(network()->isMe(ircuser)) { - network()->setChannelJoined(channel); - putCmd("MODE", params[0]); // we want to know the modes of the channel we just joined, so we ask politely - } -} - -void IrcServerHandler::handleMode(const QString &prefix, const QList ¶ms) { - if(!checkParamCount("IrcServerHandler::handleMode()", params, 2)) - return; - - if(network()->isChannelName(serverDecode(params[0]))) { - // Channel Modes - emit displayMsg(Message::Mode, BufferInfo::ChannelBuffer, serverDecode(params[0]), serverDecode(params).join(" "), prefix); - - IrcChannel *channel = network()->ircChannel(params[0]); - if(!channel) { - // we received mode information for a channel we're not in. that means probably we've just been kicked out or something like that - // anyways: we don't have a place to store the data --> discard the info. - return; - } - - QString modes = params[1]; - bool add = true; - int paramOffset = 2; - for(int c = 0; c < modes.length(); c++) { - if(modes[c] == '+') { - add = true; - continue; - } - if(modes[c] == '-') { - add = false; - continue; - } - - if(network()->prefixModes().contains(modes[c])) { - // user channel modes (op, voice, etc...) - if(paramOffset < params.count()) { - IrcUser *ircUser = network()->ircUser(params[paramOffset]); - if(!ircUser) { - qWarning() << Q_FUNC_INFO << "Unknown IrcUser:" << params[paramOffset]; - } else { - if(add) { - bool handledByNetsplit = false; - if(!_netsplits.empty()) { - foreach(Netsplit* n, _netsplits) { - handledByNetsplit = n->userAlreadyJoined(ircUser->hostmask(), channel->name()); - if(handledByNetsplit) { - n->addMode(ircUser->hostmask(), channel->name(), QString(modes[c])); - break; - } - } - } - if(!handledByNetsplit) - channel->addUserMode(ircUser, QString(modes[c])); - } - else - channel->removeUserMode(ircUser, QString(modes[c])); - } - } else { - qWarning() << "Received MODE with too few parameters:" << serverDecode(params); - } - paramOffset++; - } else { - // regular channel modes - QString value; - Network::ChannelModeType modeType = network()->channelModeType(modes[c]); - if(modeType == Network::A_CHANMODE || modeType == Network::B_CHANMODE || (modeType == Network::C_CHANMODE && add)) { - if(paramOffset < params.count()) { - value = params[paramOffset]; - } else { - qWarning() << "Received MODE with too few parameters:" << serverDecode(params); - } - paramOffset++; - } - - if(add) - channel->addChannelMode(modes[c], value); - else - channel->removeChannelMode(modes[c], value); - } - } - - } else { - // pure User Modes - IrcUser *ircUser = network()->newIrcUser(params[0]); - QString modeString(serverDecode(params[1])); - QString addModes; - QString removeModes; - bool add = false; - for(int c = 0; c < modeString.count(); c++) { - if(modeString[c] == '+') { - add = true; - continue; - } - if(modeString[c] == '-') { - add = false; - continue; - } - if(add) - addModes += modeString[c]; - else - removeModes += modeString[c]; - } - if(!addModes.isEmpty()) - ircUser->addUserModes(addModes); - if(!removeModes.isEmpty()) - ircUser->removeUserModes(removeModes); - - if(network()->isMe(ircUser)) { - network()->updatePersistentModes(addModes, removeModes); - } - - // FIXME: redirect - emit displayMsg(Message::Mode, BufferInfo::StatusBuffer, "", serverDecode(params).join(" "), prefix); - } -} - void IrcServerHandler::handleNotice(const QString &prefix, const QList ¶ms) { if(!checkParamCount("IrcServerHandler::handleNotice()", params, 2)) return; @@ -363,117 +223,6 @@ void IrcServerHandler::handlePrivmsg(const QString &prefix, const QList ¶ms) { - IrcUser *ircuser = network()->updateNickFromMask(prefix); - if(!ircuser) return; - - QString msg; - if(params.count() > 0) - msg = userDecode(ircuser->nick(), params[0]); - - // check if netsplit - if(Netsplit::isNetsplit(msg)) { - Netsplit *n; - if(!_netsplits.contains(msg)) { - n = new Netsplit(); - connect(n, SIGNAL(finished()), this, SLOT(handleNetsplitFinished())); - connect(n, SIGNAL(netsplitJoin(const QString&, const QStringList&, const QStringList&, const QString&)), - this, SLOT(handleNetsplitJoin(const QString&, const QStringList&, const QStringList&, const QString&))); - connect(n, SIGNAL(netsplitQuit(const QString&, const QStringList&, const QString&)), - this, SLOT(handleNetsplitQuit(const QString&, const QStringList&, const QString&))); - connect(n, SIGNAL(earlyJoin(const QString&, const QStringList&, const QStringList&)), - this, SLOT(handleEarlyNetsplitJoin(const QString&, const QStringList&, const QStringList&))); - _netsplits.insert(msg, n); - } - else { - n = _netsplits[msg]; - } - // add this user to the netsplit - n->userQuit(prefix, ircuser->channels(),msg); - } - // normal quit - else { - foreach(QString channel, ircuser->channels()) - emit displayMsg(Message::Quit, BufferInfo::ChannelBuffer, channel, msg, prefix); - ircuser->quit(); - } -} - -/* RPL_CHANNELMODEIS - " " */ -void IrcServerHandler::handle324(const QString &prefix, const QList ¶ms) { - Q_UNUSED(prefix); - handleMode(prefix, params); -} - -/* Handle signals from Netsplit objects */ - -void IrcServerHandler::handleNetsplitJoin(const QString &channel, const QStringList &users, const QStringList &modes, const QString& quitMessage) -{ - IrcChannel *ircChannel = network()->ircChannel(channel); - if(!ircChannel) { - return; - } - QList ircUsers; - QStringList newModes = modes; - QStringList newUsers = users; - - foreach(QString user, users) { - IrcUser *iu = network()->ircUser(nickFromMask(user)); - if(iu) - ircUsers.append(iu); - else { // the user already quit - int idx = users.indexOf(user); - newUsers.removeAt(idx); - newModes.removeAt(idx); - } - } - - QString msg = newUsers.join("#:#").append("#:#").append(quitMessage); - emit displayMsg(Message::NetsplitJoin, BufferInfo::ChannelBuffer, channel, msg); - ircChannel->joinIrcUsers(ircUsers, newModes); -} - -void IrcServerHandler::handleNetsplitQuit(const QString &channel, const QStringList &users, const QString& quitMessage) -{ - QString msg = users.join("#:#").append("#:#").append(quitMessage); - emit displayMsg(Message::NetsplitQuit, BufferInfo::ChannelBuffer, channel, msg); - foreach(QString user, users) { - IrcUser *iu = network()->ircUser(nickFromMask(user)); - if(iu) - iu->quit(); - } -} - -void IrcServerHandler::handleEarlyNetsplitJoin(const QString &channel, const QStringList &users, const QStringList &modes) { - IrcChannel *ircChannel = network()->ircChannel(channel); - if(!ircChannel) { - qDebug() << "handleEarlyNetsplitJoin(): channel " << channel << " invalid"; - return; - } - QList ircUsers; - QStringList newModes = modes; - - foreach(QString user, users) { - IrcUser *iu = network()->updateNickFromMask(user); - if(iu) { - ircUsers.append(iu); - emit displayMsg(Message::Join, BufferInfo::ChannelBuffer, channel, channel, user); - } - else { - newModes.removeAt(users.indexOf(user)); - } - } - ircChannel->joinIrcUsers(ircUsers, newModes); -} -void IrcServerHandler::handleNetsplitFinished() -{ - Netsplit* n = qobject_cast(sender()); - _netsplits.remove(_netsplits.key(n)); - n->deleteLater(); -} - -/* */ - // FIXME networkConnection()->setChannelKey("") for all ERR replies indicating that a JOIN went wrong // mostly, these are codes in the 47x range @@ -505,11 +254,6 @@ bool IrcServerHandler::checkParamCount(const QString &methodName, const QList ¶ms); - void handleMode(const QString &prefix, const QList ¶ms); void handleNotice(const QString &prefix, const QList ¶ms); void handlePing(const QString &prefix, const QList ¶ms); void handlePrivmsg(const QString &prefix, const QList ¶ms); - void handleQuit(const QString &prefix, const QList ¶ms); - void handle324(const QString &prefix, const QList ¶ms); // RPL_CHANNELMODEIS void defaultHandler(QString cmd, const QString &prefix, const QList ¶ms); -private slots: - //! Joins after a netsplit - /** This slot handles a bulk-join after a netsplit is over - * \param channel The channel the users joined - * \param users The list of users that joind the channel - * \param modes The list of modes the users get set - * \param quitMessage The message we received when the netsplit occured - */ - void handleNetsplitJoin(const QString &channel, const QStringList &users, const QStringList &modes, const QString &quitMessage); - - //! Quits after a netsplit - /** This slot handles a bulk-quit after a netsplit occured - * \param channel The channel the users quitted - * \param users The list of users that got split - * \param quitMessage The message we received when the netsplit occured - */ - void handleNetsplitQuit(const QString &channel, const QStringList &users, const QString &quitMessage); - - //! Netsplit finished - /** This slot deletes the netsplit object that sent the finished() signal - */ - void handleNetsplitFinished(); - - void handleEarlyNetsplitJoin(const QString &channel, const QStringList &users, const QStringList &modes); - - //! Destroy any existing netsplits - /** This slot deletes all netsplit objects - * Used to get rid of existing netsplits on network reconnect - */ - void destroyNetsplits(); - private: void tryNextNick(const QString &errnick, bool erroneus = false); bool checkParamCount(const QString &methodName, const QList ¶ms, int minParams); diff --git a/src/core/netsplit.cpp b/src/core/netsplit.cpp index 265521ab..bcc91eab 100644 --- a/src/core/netsplit.cpp +++ b/src/core/netsplit.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2005-09 by the Quassel Project * + * Copyright (C) 2005-2010 by the Quassel Project * * devel@quassel-irc.org * * * * This program is free software; you can redistribute it and/or modify * @@ -19,12 +19,14 @@ ***************************************************************************/ #include "netsplit.h" +#include "network.h" #include "util.h" #include -Netsplit::Netsplit() - : _quitMsg(""), _sentQuit(false), _joinCounter(0), _quitCounter(0) +Netsplit::Netsplit(Network *network, QObject *parent) + : QObject(parent), + _network(network), _quitMsg(""), _sentQuit(false), _joinCounter(0), _quitCounter(0) { _discardTimer.setSingleShot(true); _joinTimer.setSingleShot(true); @@ -133,7 +135,7 @@ void Netsplit::joinTimeout() */ if(_joinCounter < _quitCounter/3) { for(it = _joins.begin(); it != _joins.end(); ++it) - emit earlyJoin(it.key(), it.value().first, it.value().second); + emit earlyJoin(network(), it.key(), it.value().first, it.value().second); // we don't care about those anymore _joins.clear(); @@ -147,7 +149,7 @@ void Netsplit::joinTimeout() // send netsplitJoin for every recorded channel for(it = _joins.begin(); it != _joins.end(); ++it) - emit netsplitJoin(it.key(), it.value().first, it.value().second ,_quitMsg); + emit netsplitJoin(network(), it.key(), it.value().first, it.value().second ,_quitMsg); _joins.clear(); _discardTimer.stop(); emit finished(); @@ -170,7 +172,7 @@ void Netsplit::quitTimeout() // not yet sure how that could happen, but never send empty netsplit-quits // anyway. if(!usersToSend.isEmpty()) - emit netsplitQuit(channelIter.key(), usersToSend, _quitMsg); + emit netsplitQuit(network(), channelIter.key(), usersToSend, _quitMsg); } _sentQuit = true; } diff --git a/src/core/netsplit.h b/src/core/netsplit.h index e7e644b8..6e96fd4e 100644 --- a/src/core/netsplit.h +++ b/src/core/netsplit.h @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2005-09 by the Quassel Project * + * Copyright (C) 2005-2010 by the Quassel Project * * devel@quassel-irc.org * * * * This program is free software; you can redistribute it and/or modify * @@ -21,17 +21,20 @@ #ifndef NETSPLIT_H #define NETSPLIT_H -#include #include #include #include #include +class Network; + class Netsplit : public QObject { Q_OBJECT public: - Netsplit(); + Netsplit(Network *network, QObject *parent = 0); + + inline Network *network() const { return _network; } //! Add a user to the netsplit /** Call this method if you noticed a netsplit. @@ -46,7 +49,6 @@ public: //! Remove a user from the netsplit /** Call this method if a user joined after a netsplit occured. - * * \param sender The sender string of the joined user * \param channel The channel that user shares with us @@ -83,29 +85,32 @@ signals: //! A bulk-join of netsplitted users timed out /** Whenever the internal join-timer times out, we consider the bulk-join to be finished and emit that signal * for every channel. This is the end of a netsplit. + * \param net The network * \param channel The IRC channel * \param users A list of all users that joined that channel * \param modes A list of all modes the users got set after joining again * \param quitMessage The Quitmessage and thus the servers that got split */ - void netsplitJoin(const QString &channel, const QStringList &users, const QStringList &modes, const QString &quitMessage); + void netsplitJoin(Network *net, const QString &channel, const QStringList &users, const QStringList &modes, const QString &quitMessage); //! A (probably bulk-) join of netsplitted users. /** If users hit by the split joined before the netsplit is considered over, join the users with a normal join. + * \param net The network * \param channel The IRC channel * \param users A list of all users that joined that channel * \param modes A list of all modes the users got set after joining again */ - void earlyJoin(const QString &channel, const QStringList &users, const QStringList &modes); + void earlyJoin(Network *net, const QString &channel, const QStringList &users, const QStringList &modes); //! A bulk-quit of netsplitted users timed out /** Whenever the internal quit-timer times out, we consider the bulk-quit to be finished and emit that signal * for every channel. + * \param net The network * \param channel The IRC channel * \param users A list of all users that quitted in that channel * \param quitMessage The Quitmessage and thus the servers that got split */ - void netsplitQuit(const QString &channel, const QStringList &users, const QString &quitMessage); + void netsplitQuit(Network *net, const QString &channel, const QStringList &users, const QString &quitMessage); //! The Netsplit is considered finished /** This signal is emitted right after all netsplitJoin signals have been sent or whenever the @@ -119,6 +124,7 @@ private slots: void quitTimeout(); private: + Network *_network; QString _quitMsg; // key: channel name // value: senderstring, list of modes -- 2.20.1