X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=blobdiff_plain;f=src%2Fcommon%2Fignorelistmanager.cpp;h=24a26eca4fe9a3befbd5692679851680423d7da0;hp=dfd9ae2db03b1b747db4a53cb67ca5036b801ddd;hb=8961f348947fc55cc4bc769563684af3f2ea7ccc;hpb=f19fea582ace1d8f3dfe29c1096c48758079e56e diff --git a/src/common/ignorelistmanager.cpp b/src/common/ignorelistmanager.cpp index dfd9ae2d..24a26eca 100644 --- a/src/common/ignorelistmanager.cpp +++ b/src/common/ignorelistmanager.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2005-09 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 * @@ -15,166 +15,222 @@ * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ #include "ignorelistmanager.h" #include #include -#include -#include "message.h" +IgnoreListManager& IgnoreListManager::operator=(const IgnoreListManager& other) +{ + if (this == &other) + return *this; -INIT_SYNCABLE_OBJECT(IgnoreListManager) - -IgnoreListManager &IgnoreListManager::operator=(const IgnoreListManager &other) { - if(this == &other) + SyncableObject::operator=(other); + _ignoreList = other._ignoreList; return *this; - - SyncableObject::operator=(other); - _ignoreList = other._ignoreList; - return *this; } -int IgnoreListManager::indexOf(const QString &ignore) const { - for(int i = 0; i < _ignoreList.count(); i++) { - if(_ignoreList[i].ignoreRule == ignore) - return i; - } - return -1; +int IgnoreListManager::indexOf(const QString& ignore) const +{ + for (int i = 0; i < _ignoreList.count(); i++) { + if (_ignoreList[i].contents() == ignore) + return i; + } + return -1; } -QVariantMap IgnoreListManager::initIgnoreList() const { - QVariantMap ignoreListMap; - QVariantList ignoreTypeList; - QStringList ignoreRuleList; - QStringList scopeRuleList; - QVariantList isRegExList; - QVariantList scopeList; - QVariantList strictnessList; - 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; - } - - ignoreListMap["ignoreType"] = ignoreTypeList; - ignoreListMap["ignoreRule"] = ignoreRuleList; - ignoreListMap["scopeRule"] = scopeRuleList; - ignoreListMap["isRegEx"] = isRegExList; - ignoreListMap["scope"] = scopeList; - ignoreListMap["strictness"] = strictnessList; - ignoreListMap["isActive"] = isActiveList; - return ignoreListMap; +QVariantMap IgnoreListManager::initIgnoreList() const +{ + QVariantMap ignoreListMap; + QVariantList ignoreTypeList; + QStringList ignoreRuleList; + QStringList scopeRuleList; + QVariantList isRegExList; + QVariantList scopeList; + QVariantList strictnessList; + QVariantList isActiveList; + + for (int i = 0; i < _ignoreList.count(); i++) { + 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; + ignoreListMap["ignoreRule"] = ignoreRuleList; + ignoreListMap["scopeRule"] = scopeRuleList; + ignoreListMap["isRegEx"] = isRegExList; + ignoreListMap["scope"] = scopeList; + ignoreListMap["strictness"] = strictnessList; + ignoreListMap["isActive"] = isActiveList; + return ignoreListMap; } -void IgnoreListManager::initSetIgnoreList(const QVariantMap &ignoreList) { - QVariantList ignoreType = ignoreList["ignoreType"].toList(); - QStringList ignoreRule = ignoreList["ignoreRule"].toStringList(); - QStringList scopeRule = ignoreList["scopeRule"].toStringList(); - QVariantList isRegEx = ignoreList["isRegEx"].toList(); - QVariantList scope = ignoreList["scope"].toList(); - QVariantList strictness = ignoreList["strictness"].toList(); - 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)"; - 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()); - } +void IgnoreListManager::initSetIgnoreList(const QVariantMap& ignoreList) +{ + QVariantList ignoreType = ignoreList["ignoreType"].toList(); + QStringList ignoreRule = ignoreList["ignoreRule"].toStringList(); + QStringList scopeRule = ignoreList["scopeRule"].toStringList(); + QVariantList isRegEx = ignoreList["isRegEx"].toList(); + QVariantList scope = ignoreList["scope"].toList(); + QVariantList strictness = ignoreList["strictness"].toList(); + 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 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()); + } } /* 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) { - if(contains(ignoreRule)) { - return; - } +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); - _ignoreList << newItem; + 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)) + SYNC(ARG(type), ARG(ignoreRule), ARG(isRegEx), ARG(strictness), ARG(scope), ARG(scopeRule), ARG(isActive)) } -IgnoreListManager::StrictnessType IgnoreListManager::match(const Message &msg, const QString &network) { - if(!(msg.type() & (Message::Plain | Message::Notice | Message::Action))) +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 + // with properly preprocessed Messages. + if (!(msgType & (Message::Plain | Message::Notice | Message::Action))) + return UnmatchedStrictness; + + foreach (IgnoreListItem item, _ignoreList) { + if (!item.isEnabled() || item.type() == CtcpIgnore) + continue; + if (item.scope() == GlobalScope || (item.scope() == NetworkScope && item.scopeRuleMatcher().match(network)) + || (item.scope() == ChannelScope && item.scopeRuleMatcher().match(bufferName))) { + QString str; + if (item.type() == MessageIgnore) + str = msgContents; + else + str = msgSender; + + // 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; +} - foreach(IgnoreListItem item, _ignoreList) { - if(!item.isActive) - continue; - if(item.scope == GlobalScope || (item.scope == NetworkScope && scopeMatch(item.scopeRule, network)) || - (item.scope == ChannelScope && scopeMatch(item.scopeRule, msg.bufferInfo().bufferName()))) { - - QString str; - if(item.type == MessageIgnore) - str = msg.contents(); - else - str = msg.sender(); - - 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; - } - } - } - return UnmatchedStrictness; +void IgnoreListManager::removeIgnoreListItem(const QString& ignoreRule) +{ + removeAt(indexOf(ignoreRule)); + SYNC(ARG(ignoreRule)) +} + +void IgnoreListManager::toggleIgnoreRule(const QString& ignoreRule) +{ + int idx = indexOf(ignoreRule); + if (idx == -1) + return; + _ignoreList[idx].setIsEnabled(!_ignoreList[idx].isEnabled()); + SYNC(ARG(ignoreRule)) } -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; +bool IgnoreListManager::ctcpMatch(const QString sender, const QString& network, const QString& type) +{ + foreach (IgnoreListItem item, _ignoreList) { + if (!item.isEnabled()) + continue; + 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; + return false; } -void IgnoreListManager::removeIgnoreListItem(const QString &ignoreRule) { - removeAt(indexOf(ignoreRule)); - SYNC(ARG(ignoreRule)) +/************************************************************************** + * 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::toggleIgnoreRule(const QString &ignoreRule) { - int idx = indexOf(ignoreRule); - if(idx == -1) - return; - _ignoreList[idx].isActive = !_ignoreList[idx].isActive; - SYNC(ARG(ignoreRule)) +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; }