X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=blobdiff_plain;f=src%2Fcore%2Fcoresessioneventprocessor.cpp;h=bb2c211b5ca0f0ce7bb333b25bc7c7fceea7a518;hp=cb116919b735e546b6fda1b854c476e5a1ce78bc;hb=68eca2c9f0ae5acbda19a6965a2630bd4649ef24;hpb=43e0488dad735096164d3088398653097f816424 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); +}