X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=blobdiff_plain;f=src%2Fcore%2Fircparser.cpp;h=bfbc3915bfd2eacdbfc57b6c75ab1469800871d6;hp=f3db4fceab455ba03de4849452c2a9606204e690;hb=cc6e7c08709c4e761e2fd9c2e322751015497003;hpb=76db8cdfbeffaaba359c8e80cf2146da9e9e7f8a diff --git a/src/core/ircparser.cpp b/src/core/ircparser.cpp index f3db4fce..bfbc3915 100644 --- a/src/core/ircparser.cpp +++ b/src/core/ircparser.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2005-2013 by the Quassel Project * + * Copyright (C) 2005-2019 by the Quassel Project * * devel@quassel-irc.org * * * * This program is free software; you can redistribute it and/or modify * @@ -20,6 +20,8 @@ #include "ircparser.h" +#include + #include "corenetwork.h" #include "eventmanager.h" #include "ircevent.h" @@ -27,19 +29,22 @@ #include "networkevent.h" #ifdef HAVE_QCA2 -# include "cipher.h" -# include "keyevent.h" +# include "cipher.h" +# include "keyevent.h" #endif -IrcParser::IrcParser(CoreSession *session) : - QObject(session), - _coreSession(session) +IrcParser::IrcParser(CoreSession* session) + : QObject(session) + , _coreSession(session) { - connect(this, SIGNAL(newEvent(Event *)), coreSession()->eventManager(), SLOT(postEvent(Event *))); -} + // Check if raw IRC logging is enabled + _debugLogRawIrc = (Quassel::isOptionSet("debug-irc") || Quassel::isOptionSet("debug-irc-id")); + _debugLogRawNetId = Quassel::optionValue("debug-irc-id").toInt(); + connect(this, &IrcParser::newEvent, coreSession()->eventManager(), &EventManager::postEvent); +} -bool IrcParser::checkParamCount(const QString &cmd, const QList ¶ms, int minParams) +bool IrcParser::checkParamCount(const QString& cmd, const QList& params, int minParams) { if (params.count() < minParams) { qWarning() << "Expected" << minParams << "params for IRC command" << cmd << ", got:" << params; @@ -48,8 +53,7 @@ bool IrcParser::checkParamCount(const QString &cmd, const QList &par return true; } - -QByteArray IrcParser::decrypt(Network *network, const QString &bufferName, const QByteArray &message, bool isTopic) +QByteArray IrcParser::decrypt(Network* network, const QString& bufferName, const QByteArray& message, bool isTopic) { #ifdef HAVE_QCA2 if (message.isEmpty()) @@ -58,7 +62,7 @@ QByteArray IrcParser::decrypt(Network *network, const QString &bufferName, const if (!Cipher::neededFeaturesAvailable()) return message; - Cipher *cipher = qobject_cast(network)->cipher(bufferName); + Cipher* cipher = qobject_cast(network)->cipher(bufferName); if (!cipher || cipher->key().isEmpty()) return message; @@ -71,12 +75,11 @@ QByteArray IrcParser::decrypt(Network *network, const QString &bufferName, const #endif } - /* parse the raw server string and generate an appropriate event */ /* used to be handleServerMsg() */ -void IrcParser::processNetworkIncoming(NetworkDataEvent *e) +void IrcParser::processNetworkIncoming(NetworkDataEvent* e) { - CoreNetwork *net = qobject_cast(e->network()); + auto* net = qobject_cast(e->network()); if (!net) { qWarning() << "Received network event without valid network pointer!"; return; @@ -91,6 +94,12 @@ void IrcParser::processNetworkIncoming(NetworkDataEvent *e) return; } + // Log the message if enabled and network ID matches or allows all + if (_debugLogRawIrc && (_debugLogRawNetId == -1 || net->networkId().toInt() == _debugLogRawNetId)) { + // Include network ID + qDebug() << "IRC net" << net->networkId() << "<<" << msg; + } + // Now we split the raw message into its various parts... QString prefix; QByteArray trailing; @@ -140,7 +149,7 @@ void IrcParser::processNetworkIncoming(NetworkDataEvent *e) // next string without a whitespace is the command cmd = foo.trimmed(); - QList events; + QList events; EventManager::EventType type = EventManager::Invalid; uint num = cmd.toUInt(); @@ -172,24 +181,43 @@ void IrcParser::processNetworkIncoming(NetworkDataEvent *e) // nice pre-parsed events that the CTCP handler can consume. QStringList decParams; - bool defaultHandling = true; // whether to automatically copy the remaining params and send the event + bool defaultHandling = true; // whether to automatically copy the remaining params and send the event switch (type) { case EventManager::IrcEventPrivmsg: - defaultHandling = false; // this might create a list of events + defaultHandling = false; // this might create a list of events if (checkParamCount(cmd, params, 1)) { QString senderNick = nickFromMask(prefix); + net->updateNickFromMask(prefix); + // Check if the sender is our own nick. If so, treat message as if sent by ourself. + // See http://ircv3.net/specs/extensions/echo-message-3.2.html + // Cache the result to avoid multiple redundant comparisons + bool isSelfMessage = net->isMyNick(senderNick); + QByteArray msg = params.count() < 2 ? QByteArray() : params.at(1); QStringList targets = net->serverDecode(params.at(0)).split(',', QString::SkipEmptyParts); QStringList::const_iterator targetIter; for (targetIter = targets.constBegin(); targetIter != targets.constEnd(); ++targetIter) { - QString target = net->isChannelName(*targetIter) ? *targetIter : senderNick; + // For self-messages, keep the target, don't set it to the senderNick + QString target = net->isChannelName(*targetIter) || net->isStatusMsg(*targetIter) || isSelfMessage ? *targetIter : senderNick; + // Note: self-messages could be encrypted with a different key. If issues arise, + // consider including this within an if (!isSelfMessage) block msg = decrypt(net, target, msg); - events << new IrcEventRawMessage(EventManager::IrcEventRawPrivmsg, net, msg, prefix, target, e->timestamp()); + IrcEventRawMessage* rawMessage = new IrcEventRawMessage(EventManager::IrcEventRawPrivmsg, + net, + msg, + prefix, + target, + e->timestamp()); + if (isSelfMessage) { + // Self-messages need processed differently, tag as such via flag. + rawMessage->setFlag(EventManager::Self); + } + events << rawMessage; } } break; @@ -198,20 +226,27 @@ void IrcParser::processNetworkIncoming(NetworkDataEvent *e) defaultHandling = false; if (checkParamCount(cmd, params, 2)) { + // Check if the sender is our own nick. If so, treat message as if sent by ourself. + // See http://ircv3.net/specs/extensions/echo-message-3.2.html + // Cache the result to avoid multiple redundant comparisons + bool isSelfMessage = net->isMyNick(nickFromMask(prefix)); + QStringList targets = net->serverDecode(params.at(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 + // :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 (!net->isChannelName(target)) { QString decMsg = net->serverDecode(params.at(1)); - QRegExp welcomeRegExp("^\\[([^\\]]+)\\] "); + QRegExp welcomeRegExp(R"(^\[([^\]]+)\] )"); if (welcomeRegExp.indexIn(decMsg) != -1) { QString channelname = welcomeRegExp.cap(1); decMsg = decMsg.mid(welcomeRegExp.matchedLength()); - CoreIrcChannel *chan = static_cast(net->ircChannel(channelname)); // we only have CoreIrcChannels in the core, so this cast is safe + CoreIrcChannel* chan = static_cast( + net->ircChannel(channelname)); // we only have CoreIrcChannels in the core, so this cast is safe if (chan && !chan->receivedWelcomeMsg()) { chan->setReceivedWelcomeMsg(); events << new MessageEvent(Message::Notice, net, decMsg, prefix, channelname, Message::None, e->timestamp()); @@ -226,28 +261,50 @@ void IrcParser::processNetworkIncoming(NetworkDataEvent *e) else { if (!target.isEmpty() && net->prefixes().contains(target.at(0))) target = target.mid(1); - if (!net->isChannelName(target)) - target = nickFromMask(prefix); + + if (!net->isChannelName(target)) { + // For self-messages, keep the target, don't set it to the sender prefix + if (!isSelfMessage) { + target = nickFromMask(prefix); + } + net->updateNickFromMask(prefix); + } } #ifdef HAVE_QCA2 // Handle DH1080 key exchange - if (params[1].startsWith("DH1080_INIT")) { + // Don't allow key exchange in channels, and don't allow it for self-messages. + bool keyExchangeAllowed = (!net->isChannelName(target) && !isSelfMessage); + if (params[1].startsWith("DH1080_INIT") && keyExchangeAllowed) { events << new KeyEvent(EventManager::KeyEvent, net, prefix, target, KeyEvent::Init, params[1].mid(12)); - } else if (params[1].startsWith("DH1080_FINISH")) { + } + else if (params[1].startsWith("DH1080_FINISH") && keyExchangeAllowed) { events << new KeyEvent(EventManager::KeyEvent, net, prefix, target, KeyEvent::Finish, params[1].mid(14)); - } else + } + else #endif - events << new IrcEventRawMessage(EventManager::IrcEventRawNotice, net, params[1], prefix, target, e->timestamp()); + { + IrcEventRawMessage* rawMessage = new IrcEventRawMessage(EventManager::IrcEventRawNotice, + net, + params[1], + prefix, + target, + e->timestamp()); + if (isSelfMessage) { + // Self-messages need processed differently, tag as such via flag. + rawMessage->setFlag(EventManager::Self); + } + events << rawMessage; + } } } break; // the following events need only special casing for param decoding case EventManager::IrcEventKick: - if (params.count() >= 3) { // we have a reason + if (params.count() >= 3) { // we have a reason decParams << net->serverDecode(params.at(0)) << net->serverDecode(params.at(1)); - decParams << net->channelDecode(decParams.first(), params.at(2)); // kick reason + decParams << net->channelDecode(decParams.first(), params.at(2)); // kick reason } break; @@ -256,12 +313,14 @@ void IrcParser::processNetworkIncoming(NetworkDataEvent *e) QString channel = net->serverDecode(params.at(0)); decParams << channel; decParams << net->userDecode(nickFromMask(prefix), params.at(1)); + net->updateNickFromMask(prefix); } break; case EventManager::IrcEventQuit: if (params.count() >= 1) { decParams << net->userDecode(nickFromMask(prefix), params.at(0)); + net->updateNickFromMask(prefix); } break; @@ -273,6 +332,16 @@ void IrcParser::processNetworkIncoming(NetworkDataEvent *e) } break; + case EventManager::IrcEventAway: { + // Update hostmask info first. This will create the nick if it doesn't exist, e.g. + // away-notify data being sent before JOIN messages. + net->updateNickFromMask(prefix); + // Separate nick in order to separate server and user decoding + QString nick = nickFromMask(prefix); + decParams << nick; + decParams << (params.count() >= 1 ? net->userDecode(nick, params.at(0)) : QString()); + } break; + case EventManager::IrcEventNumeric: switch (num) { case 301: /* RPL_AWAY */ @@ -298,6 +367,21 @@ void IrcParser::processNetworkIncoming(NetworkDataEvent *e) decParams << net->channelDecode(channel, params.at(2)); } break; + case 451: /* You have not registered... */ + if (target.compare("CAP", Qt::CaseInsensitive) == 0) { + // :irc.server.com 451 CAP :You have not registered + // If server doesn't support capabilities, it will report this message. Turn it + // into a nicer message since it's not a real error. + defaultHandling = false; + events << new MessageEvent(Message::Server, + e->network(), + tr("Capability negotiation not supported"), + QString(), + QString(), + Message::None, + e->timestamp()); + } + break; } default: @@ -308,7 +392,12 @@ void IrcParser::processNetworkIncoming(NetworkDataEvent *e) for (int i = decParams.count(); i < params.count(); i++) decParams << net->serverDecode(params.at(i)); - IrcEvent *event; + // We want to trim the last param just in case, except for PRIVMSG and NOTICE + // ... but those happen to be the only ones not using defaultHandling anyway + if (!decParams.isEmpty() && decParams.last().endsWith(' ')) + decParams.append(decParams.takeLast().trimmed()); + + IrcEvent* event; if (type == EventManager::IrcEventNumeric) event = new IrcEventNumeric(num, net, prefix, target); else @@ -318,7 +407,7 @@ void IrcParser::processNetworkIncoming(NetworkDataEvent *e) events << event; } - foreach(Event *event, events) { + foreach (Event* event, events) { emit newEvent(event); } }