X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=blobdiff_plain;f=src%2Fcore%2Fircserverhandler.cpp;h=30f5e2adfdc91b29168a7697e2d17c7b42d3e476;hp=4355b30a6666130fe1d67c2050bab4280a365fbd;hb=513c0edce6f4c69f16e6a00c144877e8d5940096;hpb=477eadcad3381620af859e3f4f91daaa67a17cbe diff --git a/src/core/ircserverhandler.cpp b/src/core/ircserverhandler.cpp index 4355b30a..30f5e2ad 100644 --- a/src/core/ircserverhandler.cpp +++ b/src/core/ircserverhandler.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2005-09 by the Quassel Project * + * Copyright (C) 2005-10 by the Quassel Project * * devel@quassel-irc.org * * * * This program is free software; you can redistribute it and/or modify * @@ -33,12 +33,14 @@ #include IrcServerHandler::IrcServerHandler(CoreNetwork *parent) - : BasicHandler(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. */ @@ -186,9 +188,23 @@ void IrcServerHandler::handleJoin(const QString &prefix, const QList QString channel = serverDecode(params[0]); IrcUser *ircuser = network()->updateNickFromMask(prefix); - emit displayMsg(Message::Join, BufferInfo::ChannelBuffer, channel, channel, 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; - ircuser->joinChannel(channel); + 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 @@ -249,10 +265,26 @@ void IrcServerHandler::handleMode(const QString &prefix, const QList // user channel modes (op, voice, etc...) if(paramOffset < params.count()) { IrcUser *ircUser = network()->ircUser(params[paramOffset]); - if(add) - channel->addUserMode(ircUser, QString(modes[c])); - else - channel->removeUserMode(ircUser, QString(modes[c])); + 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); } @@ -339,35 +371,41 @@ void IrcServerHandler::handleNotice(const QString &prefix, const QListisChannelName(target)) { - QString msg = serverDecode(params[1]); - QRegExp welcomeRegExp("^\\[([^\\]]+)\\] "); - if(welcomeRegExp.indexIn(msg) != -1) { - QString channelname = welcomeRegExp.cap(1); - msg = msg.mid(welcomeRegExp.matchedLength()); - CoreIrcChannel *chan = static_cast(network()->ircChannel(channelname)); // we only have CoreIrcChannels in the core, so this cast is safe - if(chan && !chan->receivedWelcomeMsg()) { - chan->setReceivedWelcomeMsg(); - emit displayMsg(Message::Notice, BufferInfo::ChannelBuffer, channelname, msg, prefix); - return; + + QStringList targets = serverDecode(params[0]).split(',', QString::SkipEmptyParts); + QStringList::const_iterator targetIter; + for(targetIter = targets.constBegin(); targetIter != targets.constEnd(); targetIter++) { + QString target = *targetIter; + + // special treatment for welcome messages like: + // :ChanServ!ChanServ@services. NOTICE egst :[#apache] Welcome, this is #apache. Please read the in-channel topic message. This channel is being logged by IRSeekBot. If you have any question please see http://blog.freenode.net/?p=68 + if(!network()->isChannelName(target)) { + QString msg = serverDecode(params[1]); + QRegExp welcomeRegExp("^\\[([^\\]]+)\\] "); + if(welcomeRegExp.indexIn(msg) != -1) { + QString channelname = welcomeRegExp.cap(1); + msg = msg.mid(welcomeRegExp.matchedLength()); + CoreIrcChannel *chan = static_cast(network()->ircChannel(channelname)); // we only have CoreIrcChannels in the core, so this cast is safe + if(chan && !chan->receivedWelcomeMsg()) { + chan->setReceivedWelcomeMsg(); + emit displayMsg(Message::Notice, BufferInfo::ChannelBuffer, channelname, msg, prefix); + continue; + } } } - } - if(prefix.isEmpty() || target == "AUTH") { - target = ""; - } else { - if(!target.isEmpty() && network()->prefixes().contains(target[0])) - target = target.mid(1); - if(!network()->isChannelName(target)) - target = nickFromMask(prefix); + if(prefix.isEmpty() || target == "AUTH") { + target = ""; + } else { + if(!target.isEmpty() && network()->prefixes().contains(target[0])) + target = target.mid(1); + if(!network()->isChannelName(target)) + target = nickFromMask(prefix); + } + + network()->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 ¶ms) { @@ -428,18 +466,23 @@ void IrcServerHandler::handlePrivmsg(const QString &prefix, const QListisChannelName(target)) - target = nickFromMask(prefix); + QStringList targets = serverDecode(params[0]).split(',', QString::SkipEmptyParts); + QStringList::const_iterator targetIter; + for(targetIter = targets.constBegin(); targetIter != targets.constEnd(); targetIter++) { + const QString &target = network()->isChannelName(*targetIter) + ? *targetIter + : senderNick; - // it's possible to pack multiple privmsgs into one param using ctcp - // - > we let the ctcpHandler do the work - network()->ctcpHandler()->parse(Message::Plain, prefix, target, msg); + // it's possible to pack multiple privmsgs into one param using ctcp + // - > we let the ctcpHandler do the work + network()->ctcpHandler()->parse(Message::Plain, prefix, target, msg); + } } void IrcServerHandler::handleQuit(const QString &prefix, const QList ¶ms) { @@ -450,10 +493,32 @@ void IrcServerHandler::handleQuit(const QString &prefix, const QList if(params.count() > 0) msg = userDecode(ircuser->nick(), params[0]); - foreach(QString channel, ircuser->channels()) - emit displayMsg(Message::Quit, BufferInfo::ChannelBuffer, channel, msg, prefix); - - ircuser->quit(); + // 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(); + } } void IrcServerHandler::handleTopic(const QString &prefix, const QList ¶ms) { @@ -474,7 +539,7 @@ void IrcServerHandler::handleTopic(const QString &prefix, const QListsetTopic(topic); - emit displayMsg(Message::Server, BufferInfo::ChannelBuffer, channel->name(), tr("%1 has changed topic for %2 to: \"%3\"").arg(ircuser->nick()).arg(channel->name()).arg(topic)); + emit displayMsg(Message::Topic, BufferInfo::ChannelBuffer, channel->name(), tr("%1 has changed topic for %2 to: \"%3\"").arg(ircuser->nick()).arg(channel->name()).arg(topic)); } /* RPL_WELCOME */ @@ -873,7 +938,7 @@ void IrcServerHandler::handle331(const QString &prefix, const QList if(chan) chan->setTopic(QString()); - emit displayMsg(Message::Server, BufferInfo::ChannelBuffer, channel, tr("No topic is set for %1.").arg(channel)); + emit displayMsg(Message::Topic, BufferInfo::ChannelBuffer, channel, tr("No topic is set for %1.").arg(channel)); } /* RPL_TOPIC */ @@ -888,7 +953,7 @@ void IrcServerHandler::handle332(const QString &prefix, const QList if(chan) chan->setTopic(topic); - emit displayMsg(Message::Server, BufferInfo::ChannelBuffer, channel, tr("Topic for %1 is \"%2\"").arg(channel, topic)); + emit displayMsg(Message::Topic, BufferInfo::ChannelBuffer, channel, tr("Topic for %1 is \"%2\"").arg(channel, topic)); } /* Topic set by... */ @@ -898,7 +963,7 @@ void IrcServerHandler::handle333(const QString &prefix, const QList return; QString channel = serverDecode(params[0]); - emit displayMsg(Message::Server, BufferInfo::ChannelBuffer, channel, + emit displayMsg(Message::Topic, BufferInfo::ChannelBuffer, channel, tr("Topic set by %1 on %2") .arg(serverDecode(params[1]), QDateTime::fromTime_t(channelDecode(channel, params[2]).toUInt()).toString())); } @@ -1002,6 +1067,70 @@ void IrcServerHandler::handle433(const QString &prefix, const QList tryNextNick(errnick); } +/* 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; + + foreach(QString user, users) { + IrcUser *iu = network()->updateNickFromMask(user); + if(iu) + ircUsers.append(iu); + else { + newModes.removeAt(users.indexOf(user)); + } + } + + QString msg = users.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 @@ -1035,6 +1164,10 @@ bool IrcServerHandler::checkParamCount(const QString &methodName, const QList