diff --git a/src/search/searchrule/searchrule.cpp b/src/search/searchrule/searchrule.cpp index 67b0614..58c1b85 100644 --- a/src/search/searchrule/searchrule.cpp +++ b/src/search/searchrule/searchrule.cpp @@ -1,594 +1,594 @@ /* Copyright (c) 2015-2019 Montel Laurent This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "searchrule.h" #include "searchrule/searchrulenumerical.h" #include "searchrule/searchruledate.h" #include "searchrule/searchrulestring.h" #include "searchrule/searchrulestatus.h" #include "searchrule/searchruleencryption.h" #include "mailcommon_debug.h" #include #include #include #include #include using namespace MailCommon; static const char *const funcConfigNames[] = { "contains", "contains-not", "equals", "not-equal", "regexp", "not-regexp", "greater", "less-or-equal", "less", "greater-or-equal", "is-in-addressbook", "is-not-in-addressbook", "is-in-category", "is-not-in-category", "has-attachment", "has-no-attachment", "start-with", "not-start-with", "end-with", "not-end-with" }; static const int numFuncConfigNames = sizeof funcConfigNames / sizeof *funcConfigNames; //================================================== // // class SearchRule (was: KMFilterRule) // //================================================== SearchRule::SearchRule(const QByteArray &field, Function func, const QString &contents) : mField(field) , mFunction(func) , mContents(contents) { } SearchRule::SearchRule(const SearchRule &other) : mField(other.mField) , mFunction(other.mFunction) , mContents(other.mContents) { } const SearchRule &SearchRule::operator=(const SearchRule &other) { if (this == &other) { return *this; } mField = other.mField; mFunction = other.mFunction; mContents = other.mContents; return *this; } SearchRule::Ptr SearchRule::createInstance(const QByteArray &field, Function func, const QString &contents) { SearchRule::Ptr ret; if (field == "") { ret = SearchRule::Ptr(new SearchRuleStatus(field, func, contents)); } else if (field == "" || field == "") { ret = SearchRule::Ptr(new SearchRuleNumerical(field, func, contents)); } else if (field == "") { ret = SearchRule::Ptr(new SearchRuleDate(field, func, contents)); } else if (field == "") { ret = SearchRule::Ptr(new SearchRuleEncryption(field, func, contents)); } else { ret = SearchRule::Ptr(new SearchRuleString(field, func, contents)); } return ret; } SearchRule::Ptr SearchRule::createInstance(const QByteArray &field, const char *func, const QString &contents) { return createInstance(field, configValueToFunc(func), contents); } SearchRule::Ptr SearchRule::createInstance(const SearchRule &other) { return createInstance(other.field(), other.function(), other.contents()); } SearchRule::Ptr SearchRule::createInstanceFromConfig(const KConfigGroup &config, int aIdx) { const char cIdx = char(int('A') + aIdx); static const QString field = QStringLiteral("field"); static const QString func = QStringLiteral("func"); static const QString contents = QStringLiteral("contents"); const QByteArray &field2 = config.readEntry(field + cIdx, QString()).toLatin1(); Function func2 = configValueToFunc(config.readEntry(func + cIdx, QString()).toLatin1().constData()); const QString &contents2 = config.readEntry(contents + cIdx, QString()); if (field2 == "") { // backwards compat return SearchRule::createInstance("", func2, contents2); } else { return SearchRule::createInstance(field2, func2, contents2); } } SearchRule::Ptr SearchRule::createInstance(QDataStream &s) { QByteArray field; s >> field; QString function; s >> function; Function func = configValueToFunc(function.toUtf8().constData()); QString contents; s >> contents; return createInstance(field, func, contents); } SearchRule::~SearchRule() { } SearchRule::Function SearchRule::configValueToFunc(const char *str) { if (!str) { return FuncNone; } for (int i = 0; i < numFuncConfigNames; ++i) { if (qstricmp(funcConfigNames[i], str) == 0) { - return (Function)i; + return static_cast(i); } } return FuncNone; } QString SearchRule::functionToString(Function function) { if (function != FuncNone) { return funcConfigNames[int(function)]; } else { return QStringLiteral("invalid"); } } void SearchRule::writeConfig(KConfigGroup &config, int aIdx) const { const char cIdx = char('A' + aIdx); static const QString field = QStringLiteral("field"); static const QString func = QStringLiteral("func"); static const QString contents = QStringLiteral("contents"); config.writeEntry(field + cIdx, /*QString*/ (mField)); config.writeEntry(func + cIdx, functionToString(mFunction)); config.writeEntry(contents + cIdx, mContents); } QString SearchRule::conditionToString(Function function) { QString str; switch (function) { case FuncEquals: str = i18n("equal"); break; case FuncNotEqual: str = i18n("not equal"); break; case FuncIsGreater: str = i18n("is greater"); break; case FuncIsLessOrEqual: str = i18n("is less or equal"); break; case FuncIsLess: str = i18n("is less"); break; case FuncIsGreaterOrEqual: str = i18n("is greater or equal"); break; case FuncIsInAddressbook: str = i18n("is in addressbook"); break; case FuncIsNotInAddressbook: str = i18n("is not in addressbook"); break; case FuncIsInCategory: str = i18n("is in category"); break; case FuncIsNotInCategory: str = i18n("is in category"); break; case FuncHasAttachment: str = i18n("has an attachment"); break; case FuncHasNoAttachment: str = i18n("has not an attachment"); break; case FuncStartWith: str = i18n("start with"); break; case FuncNotStartWith: str = i18n("not start with"); break; case FuncEndWith: str = i18n("end with"); break; case FuncNotEndWith: str = i18n("not end with"); break; case FuncNone: str = i18n("none"); break; case FuncContains: str = i18n("contains"); break; case FuncContainsNot: str = i18n("not contains"); break; case FuncRegExp: str = i18n("has regexp"); break; case FuncNotRegExp: str = i18n("not regexp"); break; } return str; } void SearchRule::generateSieveScript(QStringList &requireModules, QString &code) { QString contentStr = mContents; if (mField == "") { QString comparaison; int offset = 0; switch (mFunction) { case FuncEquals: comparaison = QLatin1Char('"') + i18n("size equals not supported") + QLatin1Char('"'); break; case FuncNotEqual: comparaison = QLatin1Char('"') + i18n("size not equals not supported") + QLatin1Char('"'); break; case FuncIsGreater: comparaison = QStringLiteral(":over"); break; case FuncIsLessOrEqual: comparaison = QStringLiteral(":under"); offset = 1; break; case FuncIsLess: comparaison = QStringLiteral(":under"); break; case FuncIsGreaterOrEqual: comparaison = QStringLiteral(":over"); offset = -1; break; case FuncIsInAddressbook: case FuncIsNotInAddressbook: case FuncIsInCategory: case FuncIsNotInCategory: case FuncHasAttachment: case FuncHasNoAttachment: case FuncStartWith: case FuncNotStartWith: case FuncEndWith: case FuncNotEndWith: case FuncNone: case FuncContains: case FuncContainsNot: case FuncRegExp: case FuncNotRegExp: code += QLatin1Char('"') + i18n("\"%1\" is not supported with condition \"%2\"", QLatin1String(mField), conditionToString(mFunction)) + QLatin1Char('"'); return; } code += QStringLiteral("size %1 %2K").arg(comparaison).arg(QString::number(mContents.toInt() + offset)); } else if (mField == "") { //TODO ? code += QLatin1Char('"') + i18n(" not implemented/supported") + QLatin1Char('"'); } else if (mField == "") { //TODO ? code += QLatin1Char('"') + i18n(" not implemented/supported") + QLatin1Char('"'); } else if (mField == "contents") { //TODO ? code += QLatin1Char('"') + i18n(" not implemented/supported") + QLatin1Char('"'); } else if (mField == "") { //TODO ? code += QLatin1Char('"') + i18n(" not implemented/supported") + QLatin1Char('"'); } else if (mField == "") { //TODO ? code += QLatin1Char('"') + i18n(" not implemented/supported") + QLatin1Char('"'); } else if (mField == "") { //TODO ? code += QLatin1Char('"') + i18n(" not implemented/supported") + QLatin1Char('"'); } else if (mField == "") { code += QLatin1Char('"') + i18n(" is not supported") + QLatin1Char('"'); } else if (mField == "") { //TODO ? code += i18n(" not implemented/supported"); } else if (mField == "") { if (!requireModules.contains(QLatin1String("body"))) { requireModules << QStringLiteral("body"); } QString comparaison; bool negative = false; switch (mFunction) { case FuncNone: break; case FuncContains: comparaison = QStringLiteral(":contains"); break; case FuncContainsNot: negative = true; comparaison = QStringLiteral(":contains"); break; case FuncEquals: comparaison = QStringLiteral(":is"); break; case FuncNotEqual: comparaison = QStringLiteral(":is"); negative = true; break; case FuncRegExp: comparaison = QStringLiteral(":regex"); if (!requireModules.contains(QLatin1String("regex"))) { requireModules << QStringLiteral("regex"); } break; case FuncNotRegExp: if (!requireModules.contains(QLatin1String("regex"))) { requireModules << QStringLiteral("regex"); } comparaison = QStringLiteral(":regex"); negative = true; break; case FuncStartWith: comparaison = QStringLiteral(":regex"); if (!requireModules.contains(QLatin1String("regex"))) { requireModules << QStringLiteral("regex"); } contentStr = QLatin1Char('^') + contentStr; break; case FuncNotStartWith: comparaison = QStringLiteral(":regex"); if (!requireModules.contains(QLatin1String("regex"))) { requireModules << QStringLiteral("regex"); } comparaison = QStringLiteral(":regex"); contentStr = QLatin1Char('^') + contentStr; negative = true; break; case FuncEndWith: comparaison = QStringLiteral(":regex"); if (!requireModules.contains(QLatin1String("regex"))) { requireModules << QStringLiteral("regex"); } comparaison = QStringLiteral(":regex"); contentStr = contentStr + QLatin1Char('$'); break; case FuncNotEndWith: comparaison = QStringLiteral(":regex"); if (!requireModules.contains(QLatin1String("regex"))) { requireModules << QStringLiteral("regex"); } comparaison = QStringLiteral(":regex"); contentStr = contentStr + QLatin1Char('$'); negative = true; break; case FuncIsGreater: case FuncIsLessOrEqual: case FuncIsLess: case FuncIsGreaterOrEqual: case FuncIsInAddressbook: case FuncIsNotInAddressbook: case FuncIsInCategory: case FuncIsNotInCategory: case FuncHasAttachment: case FuncHasNoAttachment: code += QLatin1Char('"') + i18n("\"%1\" is not supported with condition \"%2\"", QLatin1String(mField), conditionToString(mFunction)) + QLatin1Char('"'); return; } code += (negative ? QStringLiteral("not ") : QString()) + QStringLiteral("body :text %1 \"%2\"").arg(comparaison, contentStr); } else { QString comparaison; bool negative = false; switch (mFunction) { case FuncNone: break; case FuncContains: comparaison = QStringLiteral(":contains"); break; case FuncContainsNot: negative = true; comparaison = QStringLiteral(":contains"); break; case FuncEquals: comparaison = QStringLiteral(":is"); break; case FuncNotEqual: comparaison = QStringLiteral(":is"); negative = true; break; case FuncRegExp: comparaison = QStringLiteral(":regex"); if (!requireModules.contains(QLatin1String("regex"))) { requireModules << QStringLiteral("regex"); } break; case FuncNotRegExp: if (!requireModules.contains(QLatin1String("regex"))) { requireModules << QStringLiteral("regex"); } comparaison = QStringLiteral(":regex"); negative = true; break; case FuncStartWith: comparaison = QStringLiteral(":regex"); if (!requireModules.contains(QLatin1String("regex"))) { requireModules << QStringLiteral("regex"); } contentStr = QLatin1Char('^') + contentStr; break; case FuncNotStartWith: comparaison = QStringLiteral(":regex"); if (!requireModules.contains(QLatin1String("regex"))) { requireModules << QStringLiteral("regex"); } comparaison = QStringLiteral(":regex"); contentStr = QLatin1Char('^') + contentStr; negative = true; break; case FuncEndWith: comparaison = QStringLiteral(":regex"); if (!requireModules.contains(QLatin1String("regex"))) { requireModules << QStringLiteral("regex"); } comparaison = QStringLiteral(":regex"); contentStr = contentStr + QLatin1Char('$'); break; case FuncNotEndWith: comparaison = QStringLiteral(":regex"); if (!requireModules.contains(QLatin1String("regex"))) { requireModules << QStringLiteral("regex"); } comparaison = QStringLiteral(":regex"); contentStr = contentStr + QLatin1Char('$'); negative = true; break; case FuncIsGreater: case FuncIsLessOrEqual: case FuncIsLess: case FuncIsGreaterOrEqual: case FuncIsInAddressbook: case FuncIsNotInAddressbook: case FuncIsInCategory: case FuncIsNotInCategory: case FuncHasAttachment: case FuncHasNoAttachment: code += QLatin1Char('"') + i18n("\"%1\" is not supported with condition \"%2\"", QLatin1String(mField), conditionToString(mFunction)) + QLatin1Char('"'); return; } code += (negative ? QStringLiteral("not ") : QString()) + QStringLiteral("header %1 \"%2\" \"%3\"").arg(comparaison).arg(QLatin1String(mField)).arg(contentStr); } } void SearchRule::setFunction(Function function) { mFunction = function; } SearchRule::Function SearchRule::function() const { return mFunction; } void SearchRule::setField(const QByteArray &field) { mField = field; } QByteArray SearchRule::field() const { return mField; } void SearchRule::setContents(const QString &contents) { mContents = contents; } QString SearchRule::contents() const { return mContents; } const QString SearchRule::asString() const { QString result = QLatin1String("\"") + QString::fromLatin1(mField) + QLatin1String("\" <"); result += functionToString(mFunction); result += QStringLiteral("> \"") + mContents + QStringLiteral("\""); return result; } Akonadi::SearchTerm::Condition SearchRule::akonadiComparator() const { switch (function()) { case SearchRule::FuncContains: case SearchRule::FuncContainsNot: return Akonadi::SearchTerm::CondContains; case SearchRule::FuncEquals: case SearchRule::FuncNotEqual: return Akonadi::SearchTerm::CondEqual; case SearchRule::FuncIsGreater: return Akonadi::SearchTerm::CondGreaterThan; case SearchRule::FuncIsGreaterOrEqual: return Akonadi::SearchTerm::CondGreaterOrEqual; case SearchRule::FuncIsLess: return Akonadi::SearchTerm::CondLessThan; case SearchRule::FuncIsLessOrEqual: return Akonadi::SearchTerm::CondLessOrEqual; case SearchRule::FuncRegExp: case SearchRule::FuncNotRegExp: //TODO is this sufficient? return Akonadi::SearchTerm::CondContains; case SearchRule::FuncStartWith: case SearchRule::FuncNotStartWith: case SearchRule::FuncEndWith: case SearchRule::FuncNotEndWith: //TODO is this sufficient? return Akonadi::SearchTerm::CondContains; default: qCDebug(MAILCOMMON_LOG) << "Unhandled function type: " << function(); } return Akonadi::SearchTerm::CondEqual; } bool SearchRule::isNegated() const { bool negate = false; switch (function()) { case SearchRule::FuncContainsNot: case SearchRule::FuncNotEqual: case SearchRule::FuncNotRegExp: case SearchRule::FuncHasNoAttachment: case SearchRule::FuncIsNotInCategory: case SearchRule::FuncIsNotInAddressbook: case SearchRule::FuncNotStartWith: case SearchRule::FuncNotEndWith: negate = true; default: break; } return negate; } QDataStream &SearchRule::operator >>(QDataStream &s) const { s << mField << functionToString(mFunction) << mContents; return s; }