X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=blobdiff_plain;f=src%2Fcommon%2Fignorelistmanager.cpp;h=077189d147dd3560568d326f32bf39005b1032b4;hp=92052915eeca4837d20dedd66e32de400aa73000;hb=cc6e7c08709c4e761e2fd9c2e322751015497003;hpb=4a5065255e652dd0c301bac0db41b7afb777ef49 diff --git a/src/common/ignorelistmanager.cpp b/src/common/ignorelistmanager.cpp index 92052915..077189d1 100644 --- a/src/common/ignorelistmanager.cpp +++ b/src/common/ignorelistmanager.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,13 +20,11 @@ #include "ignorelistmanager.h" -#include #include #include -#include +#include -INIT_SYNCABLE_OBJECT(IgnoreListManager) -IgnoreListManager &IgnoreListManager::operator=(const IgnoreListManager &other) +IgnoreListManager& IgnoreListManager::operator=(const IgnoreListManager& other) { if (this == &other) return *this; @@ -36,17 +34,15 @@ IgnoreListManager &IgnoreListManager::operator=(const IgnoreListManager &other) return *this; } - -int IgnoreListManager::indexOf(const QString &ignore) const +int IgnoreListManager::indexOf(const QString& ignore) const { for (int i = 0; i < _ignoreList.count(); i++) { - if (_ignoreList[i].ignoreRule == ignore) + if (_ignoreList[i].contents() == ignore) return i; } return -1; } - QVariantMap IgnoreListManager::initIgnoreList() const { QVariantMap ignoreListMap; @@ -59,13 +55,13 @@ QVariantMap IgnoreListManager::initIgnoreList() const QVariantList isActiveList; for (int i = 0; i < _ignoreList.count(); i++) { - ignoreTypeList << _ignoreList[i].type; - ignoreRuleList << _ignoreList[i].ignoreRule; - scopeRuleList << _ignoreList[i].scopeRule; - isRegExList << _ignoreList[i].isRegEx; - scopeList << _ignoreList[i].scope; - strictnessList << _ignoreList[i].strictness; - isActiveList << _ignoreList[i].isActive; + ignoreTypeList << _ignoreList[i].type(); + ignoreRuleList << _ignoreList[i].contents(); + scopeRuleList << _ignoreList[i].scopeRule(); + isRegExList << _ignoreList[i].isRegEx(); + scopeList << _ignoreList[i].scope(); + strictnessList << _ignoreList[i].strictness(); + isActiveList << _ignoreList[i].isEnabled(); } ignoreListMap["ignoreType"] = ignoreTypeList; @@ -78,8 +74,7 @@ QVariantMap IgnoreListManager::initIgnoreList() const return ignoreListMap; } - -void IgnoreListManager::initSetIgnoreList(const QVariantMap &ignoreList) +void IgnoreListManager::initSetIgnoreList(const QVariantMap& ignoreList) { QVariantList ignoreType = ignoreList["ignoreType"].toList(); QStringList ignoreRule = ignoreList["ignoreRule"].toStringList(); @@ -90,42 +85,50 @@ void IgnoreListManager::initSetIgnoreList(const QVariantMap &ignoreList) QVariantList isActive = ignoreList["isActive"].toList(); int count = ignoreRule.count(); - if (count != scopeRule.count() || count != isRegEx.count() || - count != scope.count() || count != strictness.count() || count != ignoreType.count() || count != isActive.count()) { - qWarning() << "Corrupted IgnoreList settings! (Count missmatch)"; + if (count != scopeRule.count() || count != isRegEx.count() || count != scope.count() || count != strictness.count() + || count != ignoreType.count() || count != isActive.count()) { + qWarning() << "Corrupted IgnoreList settings! (Count mismatch)"; return; } _ignoreList.clear(); for (int i = 0; i < ignoreRule.count(); i++) { - _ignoreList << IgnoreListItem(static_cast(ignoreType[i].toInt()), ignoreRule[i], isRegEx[i].toBool(), - static_cast(strictness[i].toInt()), static_cast(scope[i].toInt()), - scopeRule[i], isActive[i].toBool()); + _ignoreList << IgnoreListItem(static_cast(ignoreType[i].toInt()), + ignoreRule[i], + isRegEx[i].toBool(), + static_cast(strictness[i].toInt()), + static_cast(scope[i].toInt()), + scopeRule[i], + isActive[i].toBool()); } } - /* since overloaded methods aren't syncable (yet?) we can't use that anymore void IgnoreListManager::addIgnoreListItem(const IgnoreListItem &item) { - addIgnoreListItem(item.type, item.ignoreRule, item.isRegEx, item.strictness, item.scope, item.scopeRule, item.isActive); + addIgnoreListItem(item.type(), item.contents(), item.isRegEx(), item.strictness(), item.scope(), item.scopeRule(), item.isEnabled()); } */ -void IgnoreListManager::addIgnoreListItem(int type, const QString &ignoreRule, bool isRegEx, int strictness, - int scope, const QString &scopeRule, bool isActive) +void IgnoreListManager::addIgnoreListItem( + int type, const QString& ignoreRule, bool isRegEx, int strictness, int scope, const QString& scopeRule, bool isActive) { if (contains(ignoreRule)) { return; } - IgnoreListItem newItem = IgnoreListItem(static_cast(type), ignoreRule, isRegEx, static_cast(strictness), - static_cast(scope), scopeRule, isActive); + IgnoreListItem newItem = IgnoreListItem(static_cast(type), + ignoreRule, + isRegEx, + static_cast(strictness), + static_cast(scope), + scopeRule, + isActive); _ignoreList << newItem; SYNC(ARG(type), ARG(ignoreRule), ARG(isRegEx), ARG(strictness), ARG(scope), ARG(scopeRule), ARG(isActive)) } - -IgnoreListManager::StrictnessType IgnoreListManager::_match(const QString &msgContents, const QString &msgSender, Message::Type msgType, const QString &network, const QString &bufferName) +IgnoreListManager::StrictnessType IgnoreListManager::_match( + const QString& msgContents, const QString& msgSender, Message::Type msgType, const QString& network, const QString& bufferName) { // We method don't rely on a proper Message object to make this method more versatile. // This allows us to use it in the core with unprocessed Messages or in the Client @@ -133,92 +136,102 @@ IgnoreListManager::StrictnessType IgnoreListManager::_match(const QString &msgCo if (!(msgType & (Message::Plain | Message::Notice | Message::Action))) return UnmatchedStrictness; - foreach(IgnoreListItem item, _ignoreList) { - if (!item.isActive || item.type == CtcpIgnore) + foreach (IgnoreListItem item, _ignoreList) { + if (!item.isEnabled() || item.type() == CtcpIgnore) continue; - if (item.scope == GlobalScope - || (item.scope == NetworkScope && scopeMatch(item.scopeRule, network)) - || (item.scope == ChannelScope && scopeMatch(item.scopeRule, bufferName))) { + if (item.scope() == GlobalScope || (item.scope() == NetworkScope && item.scopeRuleMatcher().match(network)) + || (item.scope() == ChannelScope && item.scopeRuleMatcher().match(bufferName))) { QString str; - if (item.type == MessageIgnore) + if (item.type() == MessageIgnore) str = msgContents; else str = msgSender; - QRegExp ruleRx = QRegExp(item.ignoreRule); - ruleRx.setCaseSensitivity(Qt::CaseInsensitive); - if (!item.isRegEx) { - ruleRx.setPatternSyntax(QRegExp::Wildcard); - } - -// qDebug() << "IgnoreListManager::match: "; -// qDebug() << "string: " << str; -// qDebug() << "pattern: " << ruleRx.pattern(); -// qDebug() << "scopeRule: " << item.scopeRule; -// qDebug() << "now testing"; - if ((!item.isRegEx && ruleRx.exactMatch(str)) || - (item.isRegEx && ruleRx.indexIn(str) != -1)) { -// qDebug() << "MATCHED!"; - return item.strictness; + // qDebug() << "IgnoreListManager::match: "; + // qDebug() << "string: " << str; + // qDebug() << "pattern: " << ruleRx.pattern(); + // qDebug() << "scopeRule: " << item.scopeRule; + // qDebug() << "now testing"; + if (item.contentsMatcher().match(str)) { + return item.strictness(); } } } return UnmatchedStrictness; } - -bool IgnoreListManager::scopeMatch(const QString &scopeRule, const QString &string) const -{ - foreach(QString rule, scopeRule.split(";")) { - QRegExp ruleRx = QRegExp(rule.trimmed()); - ruleRx.setCaseSensitivity(Qt::CaseInsensitive); - ruleRx.setPatternSyntax(QRegExp::Wildcard); - if (ruleRx.exactMatch(string)) { - return true; - } - } - return false; -} - - -void IgnoreListManager::removeIgnoreListItem(const QString &ignoreRule) +void IgnoreListManager::removeIgnoreListItem(const QString& ignoreRule) { removeAt(indexOf(ignoreRule)); SYNC(ARG(ignoreRule)) } - -void IgnoreListManager::toggleIgnoreRule(const QString &ignoreRule) +void IgnoreListManager::toggleIgnoreRule(const QString& ignoreRule) { int idx = indexOf(ignoreRule); if (idx == -1) return; - _ignoreList[idx].isActive = !_ignoreList[idx].isActive; + _ignoreList[idx].setIsEnabled(!_ignoreList[idx].isEnabled()); SYNC(ARG(ignoreRule)) } - -bool IgnoreListManager::ctcpMatch(const QString sender, const QString &network, const QString &type) +bool IgnoreListManager::ctcpMatch(const QString sender, const QString& network, const QString& type) { - foreach(IgnoreListItem item, _ignoreList) { - if (!item.isActive) + foreach (IgnoreListItem item, _ignoreList) { + if (!item.isEnabled()) continue; - if (item.scope == GlobalScope || (item.scope == NetworkScope && scopeMatch(item.scopeRule, network))) { - QString sender_; - QStringList types = item.ignoreRule.split(QRegExp("\\s+"), QString::SkipEmptyParts); - - sender_ = types.takeAt(0); - - QRegExp ruleRx = QRegExp(sender_); - ruleRx.setCaseSensitivity(Qt::CaseInsensitive); - if (!item.isRegEx) - ruleRx.setPatternSyntax(QRegExp::Wildcard); - if ((!item.isRegEx && ruleRx.exactMatch(sender)) || - (item.isRegEx && ruleRx.indexIn(sender) != -1)) { - if (types.isEmpty() || types.contains(type, Qt::CaseInsensitive)) + if (item.scope() == GlobalScope || (item.scope() == NetworkScope && item.scopeRuleMatcher().match(network))) { + // For CTCP ignore rules, use ctcpSender + if (item.senderCTCPMatcher().match(sender)) { + // Sender matches, check types + if (item.ctcpTypes().isEmpty() || item.ctcpTypes().contains(type, Qt::CaseInsensitive)) { + // Either all types are blocked, or type matches return true; + } } } } return false; } + +/************************************************************************** + * IgnoreListItem + *************************************************************************/ +bool IgnoreListManager::IgnoreListItem::operator!=(const IgnoreListItem& other) const +{ + return (_type != other._type || _contents != other._contents || _isRegEx != other._isRegEx || _strictness != other._strictness + || _scope != other._scope || _scopeRule != other._scopeRule || _isEnabled != other._isEnabled); + // Don't compare ExpressionMatch objects as they are created as needed from the above +} + +void IgnoreListManager::IgnoreListItem::determineExpressions() const +{ + // Don't update if not needed + if (!_cacheInvalid) { + return; + } + + // Set up matching rules + // Message is either wildcard or regex + ExpressionMatch::MatchMode contentsMode = _isRegEx ? ExpressionMatch::MatchMode::MatchRegEx : ExpressionMatch::MatchMode::MatchWildcard; + + // Ignore rules are always case-insensitive + // Scope matching is always wildcard + // TODO: Expand upon ignore rule handling with next protocol break + + if (_type == CtcpIgnore) { + // Set up CTCP sender + _contentsMatch = {}; + _ctcpSenderMatch = ExpressionMatch(_cacheCtcpSender, contentsMode, false); + } + else { + // Set up message contents + _contentsMatch = ExpressionMatch(_contents, contentsMode, false); + _ctcpSenderMatch = {}; + } + // Scope rules are always multiple wildcard entries + // (Adding a regex option would be awesome, but requires a backwards-compatible protocol change) + _scopeRuleMatch = ExpressionMatch(_scopeRule, ExpressionMatch::MatchMode::MatchMultiWildcard, false); + + _cacheInvalid = false; +}