X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=blobdiff_plain;f=src%2Fcommon%2Fignorelistmanager.cpp;h=4871b746c9f9b8fc35af1fb633af649ef4c1083e;hp=1599cde70ccd46fa335ab92437fc8095f07a694c;hb=900cce213a6ed000b7131a05a0dec7d04b35b023;hpb=cd4f987d0d8ace10272bf1d87c788b741a9e85e8 diff --git a/src/common/ignorelistmanager.cpp b/src/common/ignorelistmanager.cpp index 1599cde7..4871b746 100644 --- a/src/common/ignorelistmanager.cpp +++ b/src/common/ignorelistmanager.cpp @@ -24,7 +24,6 @@ #include #include -INIT_SYNCABLE_OBJECT(IgnoreListManager) IgnoreListManager &IgnoreListManager::operator=(const IgnoreListManager &other) { if (this == &other) @@ -39,7 +38,7 @@ IgnoreListManager &IgnoreListManager::operator=(const IgnoreListManager &other) 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; @@ -58,13 +57,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; @@ -106,7 +105,7 @@ void IgnoreListManager::initSetIgnoreList(const QVariantMap &ignoreList) /* 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, @@ -133,13 +132,13 @@ IgnoreListManager::StrictnessType IgnoreListManager::_match(const QString &msgCo return UnmatchedStrictness; foreach(IgnoreListItem item, _ignoreList) { - if (!item.isActive || item.type == CtcpIgnore) + 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; @@ -149,10 +148,8 @@ IgnoreListManager::StrictnessType IgnoreListManager::_match(const QString &msgCo // qDebug() << "pattern: " << ruleRx.pattern(); // qDebug() << "scopeRule: " << item.scopeRule; // qDebug() << "now testing"; - if ((!item.isRegEx && item.regEx.exactMatch(str)) || - (item.isRegEx && item.regEx.indexIn(str) != -1)) { -// qDebug() << "MATCHED!"; - return item.strictness; + if (item.contentsMatcher().match(str)) { + return item.strictness(); } } } @@ -160,62 +157,6 @@ IgnoreListManager::StrictnessType IgnoreListManager::_match(const QString &msgCo } -bool IgnoreListManager::scopeMatch(const QString &scopeRule, const QString &string) const -{ - // A match happens when the string does NOT match ANY inverted rules and matches AT LEAST one - // normal rule, unless no normal rules exist (implicit wildcard match). This gives inverted - // rules higher priority regardless of ordering. - // - // TODO: After switching to Qt 5, use of this should be split into two parts, one part that - // would generate compiled QRegularExpressions for match/inverted match, regenerating it on any - // rule changes, and another part that would check each message against these compiled rules. - - // Keep track if any matches are found - bool matches = false; - // Keep track if normal rules and inverted rules are found, allowing for implicit wildcard - bool normalRuleFound = false, invertedRuleFound = false; - - // Split each scope rule by separator, ignoring empty parts - foreach(QString rule, scopeRule.split(";", QString::SkipEmptyParts)) { - // Trim whitespace from the start/end of the rule - rule = rule.trimmed(); - // Ignore empty rules - if (rule.isEmpty()) - continue; - - // Check if this is an inverted rule (starts with '!') - if (rule.startsWith("!")) { - // Inverted rule found - invertedRuleFound = true; - - // Take the reminder of the string - QRegExp ruleRx(rule.mid(1), Qt::CaseInsensitive); - ruleRx.setPatternSyntax(QRegExp::Wildcard); - if (ruleRx.exactMatch(string)) { - // Matches an inverted rule, full rule cannot match - return false; - } - } else { - // Normal rule found - normalRuleFound = true; - - QRegExp ruleRx(rule, Qt::CaseInsensitive); - ruleRx.setPatternSyntax(QRegExp::Wildcard); - if (ruleRx.exactMatch(string)) { - // Matches a normal rule, full rule might match - matches = true; - // Continue checking in case other inverted rules negate this - } - } - } - // No inverted rules matched, okay to match normally - // Return true if... - // ...we found a normal match - // ...implicit wildcard: we had inverted rules (that didn't match) and no normal rules - return matches || (invertedRuleFound && !normalRuleFound); -} - - void IgnoreListManager::removeIgnoreListItem(const QString &ignoreRule) { removeAt(indexOf(ignoreRule)); @@ -228,7 +169,7 @@ 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)) } @@ -236,24 +177,73 @@ void IgnoreListManager::toggleIgnoreRule(const QString &ignoreRule) bool IgnoreListManager::ctcpMatch(const QString sender, const QString &network, const QString &type) { foreach(IgnoreListItem item, _ignoreList) { - if (!item.isActive) + 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; +}