Ejemplo n.º 1
0
// only accept CTCPs in their simplest form, i.e. one ctcp, from start to
// end, no text around it; not as per the 'specs', but makes people happier
void CtcpParser::parseSimple(IrcEventRawMessage *e, Message::Type messagetype, QByteArray dequotedMessage, CtcpEvent::CtcpType ctcptype, Message::Flags flags)
{
    if (dequotedMessage.count(XDELIM) != 2 || dequotedMessage[0] != '\001' || dequotedMessage[dequotedMessage.count() -1] != '\001') {
        displayMsg(e, messagetype, targetDecode(e, dequotedMessage), e->prefix(), e->target(), flags);
    } else {
        int spacePos = -1;
        QString ctcpcmd, ctcpparam;

        QByteArray ctcp = xdelimDequote(dequotedMessage.mid(1, dequotedMessage.count() - 2));
        spacePos = ctcp.indexOf(' ');
        if (spacePos != -1) {
            ctcpcmd = targetDecode(e, ctcp.left(spacePos));
            ctcpparam = targetDecode(e, ctcp.mid(spacePos + 1));
        } else {
            ctcpcmd = targetDecode(e, ctcp);
            ctcpparam = QString();
        }
        ctcpcmd = ctcpcmd.toUpper();

        // we don't want to block /me messages by the CTCP ignore list
        if (ctcpcmd == QLatin1String("ACTION") || !coreSession()->ignoreListManager()->ctcpMatch(e->prefix(), e->network()->networkName(), ctcpcmd)) {
            QUuid uuid = QUuid::createUuid();
            _replies.insert(uuid, CtcpReply(coreNetwork(e), nickFromMask(e->prefix())));
            CtcpEvent *event = new CtcpEvent(EventManager::CtcpEvent, e->network(), e->prefix(), e->target(),
                ctcptype, ctcpcmd, ctcpparam, e->timestamp(), uuid);
            emit newEvent(event);
            CtcpEvent *flushEvent = new CtcpEvent(EventManager::CtcpEventFlush, e->network(), e->prefix(), e->target(),
                ctcptype, "INVALID", QString(), e->timestamp(), uuid);
            emit newEvent(flushEvent);
        }
    }
}
Ejemplo n.º 2
0
QString BufferInfo::bufferName() const
{
    if (isChannelName(_bufferName))
        return _bufferName;
    else
        return nickFromMask(_bufferName);  // FIXME get rid of global functions and use the Network stuff instead!
}
Ejemplo n.º 3
0
MessageEvent::MessageEvent(Message::Type msgType, Network *net, const QString &msg, const QString &sender, const QString &target,
    Message::Flags flags, const QDateTime &timestamp)
    : NetworkEvent(EventManager::MessageEvent, net),
    _msgType(msgType),
    _text(msg),
    _sender(sender),
    _target(target),
    _msgFlags(flags)
{
    IrcChannel *channel = network()->ircChannel(_target);
    if (!channel) {
        if (!_target.isEmpty() && network()->prefixes().contains(_target.at(0)))
            _target = _target.mid(1);

        if (_target.startsWith('$') || _target.startsWith('#'))
            _target = nickFromMask(sender);
    }

    _bufferType = bufferTypeByTarget(_target);

    if (timestamp.isValid())
        setTimestamp(timestamp);
    else
        setTimestamp(QDateTime::currentDateTime());
}
Ejemplo n.º 4
0
QString UiStyle::StyledMessage::plainSender() const {
  switch(type()) {
    case Message::Plain:
    case Message::Notice:
      return nickFromMask(sender());
    default:
      return QString();
  }
}
Ejemplo n.º 5
0
void CtcpParser::parseStandard(IrcEventRawMessage *e, Message::Type messagetype, QByteArray dequotedMessage, CtcpEvent::CtcpType ctcptype, Message::Flags flags)
{
    QByteArray ctcp;

    QList<CtcpEvent *> ctcpEvents;
    QUuid uuid; // needed to group all replies together

    // extract tagged / extended data
    int xdelimPos = -1;
    int xdelimEndPos = -1;
    int spacePos = -1;
    while ((xdelimPos = dequotedMessage.indexOf(XDELIM)) != -1) {
        if (xdelimPos > 0)
            displayMsg(e, messagetype, targetDecode(e, dequotedMessage.left(xdelimPos)), e->prefix(), e->target(), flags);

        xdelimEndPos = dequotedMessage.indexOf(XDELIM, xdelimPos + 1);
        if (xdelimEndPos == -1) {
            // no matching end delimiter found... treat rest of the message as ctcp
            xdelimEndPos = dequotedMessage.count();
        }
        ctcp = xdelimDequote(dequotedMessage.mid(xdelimPos + 1, xdelimEndPos - xdelimPos - 1));
        dequotedMessage = dequotedMessage.mid(xdelimEndPos + 1);

        //dispatch the ctcp command
        QString ctcpcmd = targetDecode(e, ctcp.left(spacePos));
        QString ctcpparam = targetDecode(e, ctcp.mid(spacePos + 1));

        spacePos = ctcp.indexOf(' ');
        if (spacePos != -1) {
            ctcpcmd = targetDecode(e, ctcp.left(spacePos));
            ctcpparam = targetDecode(e, ctcp.mid(spacePos + 1));
        }
        else {
            ctcpcmd = targetDecode(e, ctcp);
            ctcpparam = QString();
        }

        ctcpcmd = ctcpcmd.toUpper();

        // we don't want to block /me messages by the CTCP ignore list
        if (ctcpcmd == QLatin1String("ACTION") || !coreSession()->ignoreListManager()->ctcpMatch(e->prefix(), e->network()->networkName(), ctcpcmd)) {
            if (uuid.isNull())
                uuid = QUuid::createUuid();

            CtcpEvent *event = new CtcpEvent(EventManager::CtcpEvent, e->network(), e->prefix(), e->target(),
                ctcptype, ctcpcmd, ctcpparam, e->timestamp(), uuid);
            ctcpEvents << event;
        }
    }
    if (!ctcpEvents.isEmpty()) {
        _replies.insert(uuid, CtcpReply(coreNetwork(e), nickFromMask(e->prefix())));
        CtcpEvent *flushEvent = new CtcpEvent(EventManager::CtcpEventFlush, e->network(), e->prefix(), e->target(),
            ctcptype, "INVALID", QString(), e->timestamp(), uuid);
        ctcpEvents << flushEvent;
        foreach(CtcpEvent *event, ctcpEvents) {
            emit newEvent(event);
        }
Ejemplo n.º 6
0
void BasicHandler::displayMsg(Message::Type msgType, QString target, const QString &text, const QString &sender, Message::Flags flags) {
  if(!target.isEmpty() && network()->prefixes().contains(target[0]))
    target = target.mid(1);

  IrcChannel *channel = network()->ircChannel(target);
  if(!channel && (target.startsWith('$') || target.startsWith('#')))
    target = nickFromMask(sender);

  emit displayMsg(msgType, typeByTarget(target), target, text, sender, flags);
}
Ejemplo n.º 7
0
// FIXME hardcoded to 16 sender hashes
quint8 UiStyle::StyledMessage::senderHash() const {
  if(_senderHash != 0xff)
    return _senderHash;

  QString nick = nickFromMask(sender()).toLower();
  if(!nick.isEmpty()) {
    int chopCount = 0;
    while(chopCount < nick.size() && nick.at(nick.count() - 1 - chopCount) == '_')
      chopCount++;
    if(chopCount < nick.size())
      nick.chop(chopCount);
  }
  quint16 hash = qChecksum(nick.toAscii().data(), nick.toAscii().size());
  return (_senderHash = (hash & 0xf) + 1);
}
Ejemplo n.º 8
0
IrcUser::IrcUser(const QString &hostmask, Network *network) : SyncableObject(network),
    _initialized(false),
    _nick(nickFromMask(hostmask)),
    _user(userFromMask(hostmask)),
    _host(hostFromMask(hostmask)),
    _realName(),
    _awayMessage(),
    _away(false),
    _server(),
    // _idleTime(QDateTime::currentDateTime()),
    _ircOperator(),
    _lastAwayMessage(0),
    _whoisServiceReply(),
    _network(network),
    _codecForEncoding(0),
    _codecForDecoding(0)
{
  updateObjectName();
}
Ejemplo n.º 9
0
  params << serverEncode(bufname) << lowLevelQuote(pack(serverEncode(ctcpTag), userEncode(bufname, message)));
  emit putCmd("NOTICE", params);
}

//******************************/
// CTCP HANDLER
//******************************/
void CtcpHandler::handleAction(CtcpType ctcptype, const QString &prefix, const QString &target, const QString &param) {
  Q_UNUSED(ctcptype)
  emit displayMsg(Message::Action, typeByTarget(target), target, param, prefix);
}

void CtcpHandler::handlePing(CtcpType ctcptype, const QString &prefix, const QString &target, const QString &param) {
  Q_UNUSED(target)
  if(ctcptype == CtcpQuery) {
    reply(nickFromMask(prefix), "PING", param);
    emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("Received CTCP PING request from %1").arg(prefix));
  } else {
    // display ping answer
    uint now = QDateTime::currentDateTime().toTime_t();
    uint then = QDateTime().fromTime_t(param.toInt()).toTime_t();
    emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("Received CTCP PING answer from %1 with %2 seconds round trip time").arg(prefix).arg(now-then));
  }
}

void CtcpHandler::handleVersion(CtcpType ctcptype, const QString &prefix, const QString &target, const QString &param) {
  Q_UNUSED(target)
  if(ctcptype == CtcpQuery) {
    reply(nickFromMask(prefix), "VERSION", QString("Quassel IRC %1 (built on %2) -- http://www.quassel-irc.org")
        .arg(Quassel::buildInfo().plainVersionString)
        .arg(Quassel::buildInfo().buildDate));
void ContextMenuActionProvider::addIgnoreMenu(QMenu *menu, const QString &hostmask, const QMap<QString, bool> &ignoreMap)
{
    QMenu *ignoreMenu = _nickIgnoreMenuAction->menu();
    ignoreMenu->clear();
    QString nick = nickFromMask(hostmask);
    QString ident = userFromMask(hostmask);
    QString host = hostFromMask(hostmask);
    QString domain = host;
    QRegExp domainRx = QRegExp("(\\.[^.]+\\.\\w+\\D)$");
    if (domainRx.indexIn(host) != -1)
        domain = domainRx.cap(1);
    // we can't rely on who-data
    // if we don't have the data, we skip actions where we would need it
    bool haveWhoData = !ident.isEmpty() && !host.isEmpty();

    // add "Add Ignore Rule" description
    ignoreMenu->addAction(_ignoreDescriptions.at(0));

    if (haveWhoData) {
        QString text;
        text = QString("*!%1@%2").arg(ident, host);
        action(NickIgnoreUser)->setText(text);
        action(NickIgnoreUser)->setProperty("ignoreRule", text);

        text = QString("*!*@%1").arg(host);
        action(NickIgnoreHost)->setText(text);
        action(NickIgnoreHost)->setProperty("ignoreRule", text);

        text = domain.at(0) == '.' ? QString("*!%1@*%2").arg(ident, domain)
               : QString("*!%1@%2").arg(ident, domain);

        action(NickIgnoreDomain)->setText(text);
        action(NickIgnoreDomain)->setProperty("ignoreRule", text);

        if (!ignoreMap.contains(action(NickIgnoreUser)->property("ignoreRule").toString()))
            ignoreMenu->addAction(action(NickIgnoreUser));
        if (!ignoreMap.contains(action(NickIgnoreHost)->property("ignoreRule").toString()))
            ignoreMenu->addAction(action(NickIgnoreHost));
        // we only add that NickIgnoreDomain if it isn't the same as NickIgnoreUser
        // as happens with @foobar.com hostmasks and ips
        if (!ignoreMap.contains(action(NickIgnoreDomain)->property("ignoreRule").toString())
            && action(NickIgnoreUser)->property("ignoreRule").toString() != action(NickIgnoreDomain)->property("ignoreRule").toString())
            ignoreMenu->addAction(action(NickIgnoreDomain));
    }

    action(NickIgnoreCustom)->setProperty("ignoreRule", hostmask);
    ignoreMenu->addAction(action(NickIgnoreCustom));

    ignoreMenu->addSeparator();

    if (haveWhoData) {
        QMap<QString, bool>::const_iterator ruleIter = ignoreMap.begin();
        int counter = 0;
        if (!ignoreMap.isEmpty())
            // add "Existing Rules" description
            ignoreMenu->addAction(_ignoreDescriptions.at(1));
        while (ruleIter != ignoreMap.constEnd()) {
            if (counter < 5) {
                ActionType type = static_cast<ActionType>(NickIgnoreToggleEnabled0 + counter*0x100000);
                Action *act = action(type);
                act->setText(ruleIter.key());
                act->setProperty("ignoreRule", ruleIter.key());
                act->setChecked(ruleIter.value());
                ignoreMenu->addAction(act);
            }
            counter++;
            ++ruleIter;
        }
        if (counter)
            ignoreMenu->addSeparator();
    }
    ignoreMenu->addAction(action(ShowIgnoreList));
    addAction(_nickIgnoreMenuAction, menu);
}
Ejemplo n.º 11
0
void UiStyle::StyledMessage::style() const
{
    QString user = userFromMask(sender());
    QString host = hostFromMask(sender());
    QString nick = nickFromMask(sender());
    QString txt = UiStyle::mircToInternal(contents());
    QString bufferName = bufferInfo().bufferName();
    bufferName.replace('%', "%%"); // well, you _can_ have a % in a buffername apparently... -_-
    host.replace('%', "%%");     // hostnames too...
    user.replace('%', "%%");     // and the username...
    nick.replace('%', "%%");     // ... and then there's totally RFC-violating servers like justin.tv m(
    const int maxNetsplitNicks = 15;

    QString t;
    switch (type()) {
    case Message::Plain:
        //: Plain Message
        t = tr("%1").arg(txt); break;
    case Message::Notice:
        //: Notice Message
        t = tr("%1").arg(txt); break;
    case Message::Action:
        //: Action Message
        t = tr("%DN%1%DN %2").arg(nick).arg(txt);
        break;
    case Message::Nick:
        //: Nick Message
        if (nick == contents()) t = tr("You are now known as %DN%1%DN").arg(txt);
        else t = tr("%DN%1%DN is now known as %DN%2%DN").arg(nick, txt);
        break;
    case Message::Mode:
        //: Mode Message
        if (nick.isEmpty()) t = tr("User mode: %DM%1%DM").arg(txt);
        else t = tr("Mode %DM%1%DM by %DN%2%DN").arg(txt, nick);
        break;
    case Message::Join:
        //: Join Message
        t = tr("%DN%1%DN %DH(%2@%3)%DH has joined %DC%4%DC").arg(nick, user, host, bufferName); break;
    case Message::Part:
        //: Part Message
        t = tr("%DN%1%DN %DH(%2@%3)%DH has left %DC%4%DC").arg(nick, user, host, bufferName);
        if (!txt.isEmpty()) t = QString("%1 (%2)").arg(t).arg(txt);
        break;
    case Message::Quit:
        //: Quit Message
        t = tr("%DN%1%DN %DH(%2@%3)%DH has quit").arg(nick, user, host);
        if (!txt.isEmpty()) t = QString("%1 (%2)").arg(t).arg(txt);
        break;
    case Message::Kick:
    {
        QString victim = txt.section(" ", 0, 0);
        QString kickmsg = txt.section(" ", 1);
        //: Kick Message
        t = tr("%DN%1%DN has kicked %DN%2%DN from %DC%3%DC").arg(nick).arg(victim).arg(bufferName);
        if (!kickmsg.isEmpty()) t = QString("%1 (%2)").arg(t).arg(kickmsg);
    }
    break;
    //case Message::Kill: FIXME

    case Message::Server:
        //: Server Message
        t = tr("%1").arg(txt); break;
    case Message::Info:
        //: Info Message
        t = tr("%1").arg(txt); break;
    case Message::Error:
        //: Error Message
        t = tr("%1").arg(txt); break;
    case Message::DayChange:
    {
        //: Day Change Message
        t = tr("{Day changed to %1}").arg(timestamp().date().toString(Qt::DefaultLocaleLongDate));
    }
        break;
    case Message::Topic:
        //: Topic Message
        t = tr("%1").arg(txt); break;
    case Message::NetsplitJoin:
    {
        QStringList users = txt.split("#:#");
        QStringList servers = users.takeLast().split(" ");

        for (int i = 0; i < users.count() && i < maxNetsplitNicks; i++)
            users[i] = nickFromMask(users.at(i));

        t = tr("Netsplit between %DH%1%DH and %DH%2%DH ended. Users joined: ").arg(servers.at(0), servers.at(1));
        if (users.count() <= maxNetsplitNicks)
            t.append(QString("%DN%1%DN").arg(users.join(", ")));
        else
            t.append(tr("%DN%1%DN (%2 more)").arg(static_cast<QStringList>(users.mid(0, maxNetsplitNicks)).join(", ")).arg(users.count() - maxNetsplitNicks));
    }
    break;
    case Message::NetsplitQuit:
    {
        QStringList users = txt.split("#:#");
        QStringList servers = users.takeLast().split(" ");

        for (int i = 0; i < users.count() && i < maxNetsplitNicks; i++)
            users[i] = nickFromMask(users.at(i));

        t = tr("Netsplit between %DH%1%DH and %DH%2%DH. Users quit: ").arg(servers.at(0), servers.at(1));

        if (users.count() <= maxNetsplitNicks)
            t.append(QString("%DN%1%DN").arg(users.join(", ")));
        else
            t.append(tr("%DN%1%DN (%2 more)").arg(static_cast<QStringList>(users.mid(0, maxNetsplitNicks)).join(", ")).arg(users.count() - maxNetsplitNicks));
    }
    break;
    case Message::Invite:
        //: Invite Message
        t = tr("%1").arg(txt); break;
    default:
        t = tr("[%1]").arg(txt);
    }
    _contents = UiStyle::styleString(t, UiStyle::formatType(type()));
}
Ejemplo n.º 12
0
/* used to be handleServerMsg()                                  */
void IrcParser::processNetworkIncoming(NetworkDataEvent *e)
{
    CoreNetwork *net = qobject_cast<CoreNetwork *>(e->network());
    if (!net) {
        qWarning() << "Received network event without valid network pointer!";
        return;
    }

    // note that the IRC server is still alive
    net->resetPingTimeout();

    QByteArray msg = e->data();
    if (msg.isEmpty()) {
        qWarning() << "Received empty string from server!";
        return;
    }

    // Now we split the raw message into its various parts...
    QString prefix;
    QByteArray trailing;
    QString cmd, target;

    // First, check for a trailing parameter introduced by " :", since this might screw up splitting the msg
    // NOTE: This assumes that this is true in raw encoding, but well, hopefully there are no servers running in japanese on protocol level...
    int idx = msg.indexOf(" :");
    if (idx >= 0) {
        if (msg.length() > idx + 2)
            trailing = msg.mid(idx + 2);
        msg = msg.left(idx);
    }
    // OK, now it is safe to split...
    QList<QByteArray> params = msg.split(' ');

    // This could still contain empty elements due to (faulty?) ircds sending multiple spaces in a row
    // Also, QByteArray is not nearly as convenient to work with as QString for such things :)
    QList<QByteArray>::iterator iter = params.begin();
    while (iter != params.end()) {
        if (iter->isEmpty())
            iter = params.erase(iter);
        else
            ++iter;
    }

    if (!trailing.isEmpty())
        params << trailing;
    if (params.count() < 1) {
        qWarning() << "Received invalid string from server!";
        return;
    }

    QString foo = net->serverDecode(params.takeFirst());

    // a colon as the first chars indicates the existence of a prefix
    if (foo[0] == ':') {
        foo.remove(0, 1);
        prefix = foo;
        if (params.count() < 1) {
            qWarning() << "Received invalid string from server!";
            return;
        }
        foo = net->serverDecode(params.takeFirst());
    }

    // next string without a whitespace is the command
    cmd = foo.trimmed();

    QList<Event *> events;
    EventManager::EventType type = EventManager::Invalid;

    uint num = cmd.toUInt();
    if (num > 0) {
        // numeric reply
        if (params.count() == 0) {
            qWarning() << "Message received from server violates RFC and is ignored!" << msg;
            return;
        }
        // numeric replies have the target as first param (RFC 2812 - 2.4). this is usually our own nick. Remove this!
        target = net->serverDecode(params.takeFirst());
        type = EventManager::IrcEventNumeric;
    }
    else {
        // any other irc command
        QString typeName = QLatin1String("IrcEvent") + cmd.at(0).toUpper() + cmd.mid(1).toLower();
        type = eventManager()->eventTypeByName(typeName);
        if (type == EventManager::Invalid) {
            type = eventManager()->eventTypeByName("IrcEventUnknown");
            Q_ASSERT(type != EventManager::Invalid);
        }
        target = QString();
    }

    // Almost always, all params are server-encoded. There's a few exceptions, let's catch them here!
    // Possibly not the best option, we might want something more generic? Maybe yet another layer of
    // unencoded events with event handlers for the exceptions...
    // Also, PRIVMSG and NOTICE need some special handling, we put this in here as well, so we get out
    // 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

    switch (type) {
    case EventManager::IrcEventPrivmsg:
        defaultHandling = false; // this might create a list of events

        if (checkParamCount(cmd, params, 1)) {
            QString senderNick = nickFromMask(prefix);
            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;

                msg = decrypt(net, target, msg);

                events << new IrcEventRawMessage(EventManager::IrcEventRawPrivmsg, net, msg, prefix, target, e->timestamp());
            }
        }
        break;

    case EventManager::IrcEventNotice:
        defaultHandling = false;

        if (checkParamCount(cmd, params, 2)) {
            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
                if (!net->isChannelName(target)) {
                    QString decMsg = net->serverDecode(params.at(1));
                    QRegExp welcomeRegExp("^\\[([^\\]]+)\\] ");
                    if (welcomeRegExp.indexIn(decMsg) != -1) {
                        QString channelname = welcomeRegExp.cap(1);
                        decMsg = decMsg.mid(welcomeRegExp.matchedLength());
                        CoreIrcChannel *chan = static_cast<CoreIrcChannel *>(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());
                            continue;
                        }
                    }
                }

                if (prefix.isEmpty() || target == "AUTH") {
                    target = QString();
                }
                else {
                    if (!target.isEmpty() && net->prefixes().contains(target.at(0)))
                        target = target.mid(1);
                    if (!net->isChannelName(target))
                        target = nickFromMask(prefix);
                }

#ifdef HAVE_QCA2
                // Handle DH1080 key exchange
                if (params[1].startsWith("DH1080_INIT") && !net->isChannelName(target)) {
                    events << new KeyEvent(EventManager::KeyEvent, net, prefix, target, KeyEvent::Init, params[1].mid(12));
                } else if (params[1].startsWith("DH1080_FINISH") && !net->isChannelName(target)) {
                    events << new KeyEvent(EventManager::KeyEvent, net, prefix, target, KeyEvent::Finish, params[1].mid(14));
                } else
#endif
                    events << new IrcEventRawMessage(EventManager::IrcEventRawNotice, net, params[1], prefix, target, e->timestamp());
            }
        }
        break;

    // the following events need only special casing for param decoding
    case EventManager::IrcEventKick:
        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
        }
        break;

    case EventManager::IrcEventPart:
        if (params.count() >= 2) {
            QString channel = net->serverDecode(params.at(0));
            decParams << channel;
            decParams << net->userDecode(nickFromMask(prefix), params.at(1));
        }
        break;

    case EventManager::IrcEventQuit:
        if (params.count() >= 1) {
            decParams << net->userDecode(nickFromMask(prefix), params.at(0));
        }
        break;

    case EventManager::IrcEventTopic:
        if (params.count() >= 1) {
            QString channel = net->serverDecode(params.at(0));
            decParams << channel;
            decParams << (params.count() >= 2 ? net->channelDecode(channel, decrypt(net, channel, params.at(1), true)) : QString());
        }
        break;

    case EventManager::IrcEventNumeric:
        switch (num) {
        case 301: /* RPL_AWAY */
            if (params.count() >= 2) {
                QString nick = net->serverDecode(params.at(0));
                decParams << nick;
                decParams << net->userDecode(nick, params.at(1));
            }
            break;

        case 332: /* RPL_TOPIC */
            if (params.count() >= 2) {
                QString channel = net->serverDecode(params.at(0));
                decParams << channel;
                decParams << net->channelDecode(channel, decrypt(net, channel, params.at(1), true));
            }
            break;

        case 333: /* Topic set by... */
            if (params.count() >= 3) {
                QString channel = net->serverDecode(params.at(0));
                decParams << channel << net->serverDecode(params.at(1));
                decParams << net->channelDecode(channel, params.at(2));
            }
            break;
        }

    default:
        break;
    }

    if (defaultHandling && type != EventManager::Invalid) {
        for (int i = decParams.count(); i < params.count(); i++)
            decParams << net->serverDecode(params.at(i));

        // 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
            event = new IrcEvent(type, net, prefix);
        event->setParams(decParams);
        event->setTimestamp(e->timestamp());
        events << event;
    }

    foreach(Event *event, events) {
        emit newEvent(event);
    }
Ejemplo n.º 13
0
bool MessageFilter::filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const
{
    Q_UNUSED(sourceParent);
    QModelIndex sourceIdx = sourceModel()->index(sourceRow, 2);
    Message::Type messageType = (Message::Type)sourceIdx.data(MessageModel::TypeRole).toInt();

    // apply message type filter
    if (_messageTypeFilter & messageType)
        return false;

    if (_validBuffers.isEmpty())
        return true;

    BufferId bufferId = sourceIdx.data(MessageModel::BufferIdRole).value<BufferId>();
    if (!bufferId.isValid()) {
        return true;
    }

    // MsgId msgId = sourceIdx.data(MessageModel::MsgIdRole).value<MsgId>();
    Message::Flags flags = (Message::Flags)sourceIdx.data(MessageModel::FlagsRole).toInt();

    NetworkId myNetworkId = networkId();
    NetworkId msgNetworkId = Client::networkModel()->networkId(bufferId);
    if (myNetworkId != msgNetworkId)
        return false;

    // ignorelist handling
    // only match if message is not flagged as server msg
    if (!(flags & Message::ServerMsg) && Client::ignoreListManager()
        && Client::ignoreListManager()->match(sourceIdx.data(MessageModel::MessageRole).value<Message>(),
                                              Client::networkModel()->networkName(bufferId)))
        return false;

    if (flags & Message::Redirected) {
        int redirectionTarget = 0;
        switch (messageType) {
        case Message::Notice:
            if (Client::networkModel()->bufferType(bufferId) != BufferInfo::ChannelBuffer) {
                if (flags & Message::ServerMsg) {
                    // server notice
                    redirectionTarget = _serverNoticesTarget;
                }
                else {
                    redirectionTarget = _userNoticesTarget;
                }
            }
            break;
        case Message::Error:
            redirectionTarget = _errorMsgsTarget;
            break;
        default:
            break;
        }

        if (redirectionTarget & BufferSettings::DefaultBuffer && _validBuffers.contains(bufferId))
            return true;

        if (redirectionTarget & BufferSettings::CurrentBuffer && !(flags & Message::Backlog)) {
            BufferId redirectedTo = sourceModel()->data(sourceIdx, MessageModel::RedirectedToRole).value<BufferId>();
            if (!redirectedTo.isValid()) {
                BufferId redirectedTo = Client::bufferModel()->currentIndex().data(NetworkModel::BufferIdRole).value<BufferId>();
                if (redirectedTo.isValid())
                    sourceModel()->setData(sourceIdx, QVariant::fromValue<BufferId>(redirectedTo), MessageModel::RedirectedToRole);
            }

            if (_validBuffers.contains(redirectedTo))
                return true;
        }

        if (redirectionTarget & BufferSettings::StatusBuffer) {
            QSet<BufferId>::const_iterator idIter = _validBuffers.constBegin();
            while (idIter != _validBuffers.constEnd()) {
                if (Client::networkModel()->bufferType(*idIter) == BufferInfo::StatusBuffer)
                    return true;
                ++idIter;
            }
        }

        return false;
    }

    if (_validBuffers.contains(bufferId)) {
        return true;
    }
    else {
        // show Quit messages in Query buffers:
        if (bufferType() != BufferInfo::QueryBuffer)
            return false;
        if (!(messageType & Message::Quit))
            return false;

        if (myNetworkId != msgNetworkId)
            return false;

        // Extract timestamp and nickname from the new quit message
        qint64 messageTimestamp = sourceModel()->data(sourceIdx, MessageModel::TimestampRole).value<QDateTime>().toMSecsSinceEpoch();
        QString quiter = nickFromMask(sourceModel()->data(sourceIdx, MessageModel::MessageRole).value<Message>().sender()).toLower();

        // Check that nickname matches query name
        if (quiter != bufferName().toLower())
            return false;

        // Check if a quit message was already forwarded within +/- 1000 ms
        static constexpr qint64 MAX_QUIT_DELTA_MS = 1 * 1000;
        // No need to check if it's the appropriate buffer, each query has a unique message filter
        if (std::binary_search(_filteredQuitMsgTime.begin(), _filteredQuitMsgTime.end(), messageTimestamp, [](qint64 a, qint64 b) {
                return ((a + MAX_QUIT_DELTA_MS) < b);
            })) {
            // New element is less than if at least 1000 ms older/newer
            // Match found, no need to forward another quit message
            return false;
        }

        // Mark query as having a quit message inserted
        auto* that = const_cast<MessageFilter*>(this);
        that->_filteredQuitMsgTime.insert(messageTimestamp);
        return true;
    }
}