1 /* 2 SPDX-FileCopyrightText: 2015-2021 Laurent Montel <montel@kde.org> 3 4 SPDX-License-Identifier: GPL-2.0-or-later 5 */ 6 #pragma once 7 8 #include "mailcommon_export.h" 9 #include <Akonadi/SearchQuery> 10 11 #include <Akonadi/Item> 12 13 class KConfigGroup; 14 namespace MailCommon 15 { 16 /** 17 * @short This class represents one search pattern rule. 18 * Incoming mail is sent through the list of mail filter 19 * rules before it is placed in the associated mail folder (usually "inbox"). 20 * This class represents one mail filter rule. It is also used to represent 21 * a search rule as used by the search dialog and folders. 22 */ 23 class MAILCOMMON_EXPORT SearchRule 24 { 25 public: 26 /** 27 * Defines a pointer to a search rule. 28 */ 29 using Ptr = std::shared_ptr<SearchRule>; 30 31 /** 32 * Describes operators for comparison of field and contents. 33 * 34 * If you change the order or contents of the enum: do not forget 35 * to change funcConfigNames[], sFilterFuncList and matches() 36 * in SearchRule, too. 37 * Also, it is assumed that these functions come in pairs of logical 38 * opposites (ie. "=" <-> "!=", ">" <-> "<=", etc.). 39 */ 40 enum Function { 41 FuncNone = -1, 42 FuncContains = 0, 43 FuncContainsNot, 44 FuncEquals, 45 FuncNotEqual, 46 FuncRegExp, 47 FuncNotRegExp, 48 FuncIsGreater, 49 FuncIsLessOrEqual, 50 FuncIsLess, 51 FuncIsGreaterOrEqual, 52 FuncIsInAddressbook, 53 FuncIsNotInAddressbook, 54 FuncIsInCategory, 55 FuncIsNotInCategory, 56 FuncHasAttachment, 57 FuncHasNoAttachment, 58 FuncStartWith, 59 FuncNotStartWith, 60 FuncEndWith, 61 FuncNotEndWith 62 }; 63 64 /** 65 * @enum RequiredPart 66 * @brief Possible required parts. 67 */ 68 enum RequiredPart { 69 Envelope = 0, ///< Envelope 70 Header, ///< Header 71 CompleteMessage ///< Whole message 72 }; 73 74 /** 75 * Creates new new search rule. 76 * 77 * @param field The field to search in. 78 * @param function The function to use for searching. 79 * @param contents The contents to search for. 80 */ 81 explicit SearchRule(const QByteArray &field = QByteArray(), Function function = FuncContains, const QString &contents = QString()); 82 83 /** 84 * Creates a new search rule from an @p other rule. 85 */ 86 SearchRule(const SearchRule &other); 87 88 /** 89 * Initializes this rule with an @p other rule. 90 */ 91 const SearchRule &operator=(const SearchRule &other); 92 93 /** 94 * Creates a new search rule of a certain type by instantiating the 95 * appropriate subclass depending on the @p field. 96 * 97 * @param field The field to search in. 98 * @param function The function to use for searching. 99 * @param contents The contents to search for. 100 */ 101 static SearchRule::Ptr createInstance(const QByteArray &field = QByteArray(), Function function = FuncContains, const QString &contents = QString()); 102 103 /** 104 * Creates a new search rule of a certain type by instantiating the 105 * appropriate subclass depending on the @p field. 106 * 107 * @param field The field to search in. 108 * @param function The name of the function to use for searching. 109 * @param contents The contents to search for. 110 */ 111 static SearchRule::Ptr createInstance(const QByteArray &field, const char *function, const QString &contents); 112 113 /** 114 * Creates a new search rule by cloning an @p other rule. 115 */ 116 static SearchRule::Ptr createInstance(const SearchRule &other); 117 118 /** 119 * Creates a new search rule by deseralizing its structure from a data @p stream. 120 */ 121 static SearchRule::Ptr createInstance(QDataStream &stream); 122 123 /** 124 * Creates a new search rule from a given config @p group. 125 * 126 * @param group The config group to read the structure from. 127 * @param index The identifier that is used to distinguish 128 * rules within a single config group. 129 * 130 * @note This function does no validation of the data obtained 131 * from the config file. You should call isEmpty yourself 132 * if you need valid rules. 133 */ 134 static SearchRule::Ptr createInstanceFromConfig(const KConfigGroup &group, int index); 135 136 /** 137 * Destroys the search rule. 138 */ 139 virtual ~SearchRule(); 140 141 /** 142 * Tries to match the rule against the KMime::Message in the 143 * given @p item. 144 * 145 * @return true if the rule matched, false otherwise. 146 * 147 * @note Must be implemented by subclasses. 148 */ 149 virtual bool matches(const Akonadi::Item &item) const = 0; 150 151 /** 152 * Determines whether the rule is worth considering. 153 * It isn't if either the field is not set or the contents is empty. 154 * The calling code should make sure that it's rule list contains 155 * only non-empty rules, as matches doesn't check this. 156 */ 157 virtual bool isEmpty() const = 0; 158 159 /** 160 * Returns the required part from the item that is needed for the search to 161 * operate. See @ref RequiredPart */ 162 virtual SearchRule::RequiredPart requiredPart() const = 0; 163 164 /** 165 * Saves the object into a given config @p group. 166 * 167 * @param group The config group. 168 * @param index The identifier that is used to distinguish 169 * rules within a single config group. 170 * 171 * @note This function will happily write itself even when it's 172 * not valid, assuming higher layers to Do The Right Thing(TM). 173 */ 174 void writeConfig(KConfigGroup &group, int index) const; 175 176 void generateSieveScript(QStringList &requireModules, QString &code); 177 178 /** 179 * Sets the filter @p function of the rule. 180 */ 181 void setFunction(Function function); 182 183 /** 184 * Returns the filter function of the rule. 185 */ 186 Function function() const; 187 188 /** 189 * Sets the message header field @p name. 190 * 191 * @note Make sure the name contains no trailing ':'. 192 */ 193 void setField(const QByteArray &name); 194 195 /** 196 * Returns the message header field name (without the trailing ':'). 197 * 198 * There are also six pseudo-headers: 199 * @li \<message\>: Try to match against the whole message. 200 * @li \<body\>: Try to match against the body of the message. 201 * @li \<any header\>: Try to match against any header field. 202 * @li \<recipients\>: Try to match against both To: and Cc: header fields. 203 * @li \<size\>: Try to match against size of message (numerical). 204 * @li \<age in days\>: Try to match against age of message (numerical). 205 * @li \<status\>: Try to match against status of message (status). 206 * @li \<tag\>: Try to match against message tags. 207 */ 208 QByteArray field() const; 209 210 /** 211 * Set the @p contents of the rule. 212 * 213 * This can be either a substring to search for in 214 * or a regexp pattern to match against the header. 215 */ 216 void setContents(const QString &contents); 217 218 /** 219 * Returns the contents of the rule. 220 */ 221 QString contents() const; 222 223 /** 224 * Returns the rule as string for debugging purpose 225 */ 226 const QString asString() const; 227 228 /** 229 * Adds query terms to the given term group. 230 */ addQueryTerms(Akonadi::SearchTerm & groupTerm,bool & emptyIsNotAnError)231 virtual void addQueryTerms(Akonadi::SearchTerm &groupTerm, bool &emptyIsNotAnError) const 232 { 233 Q_UNUSED(groupTerm) 234 Q_UNUSED(emptyIsNotAnError) 235 } 236 237 QDataStream &operator>>(QDataStream &) const; informationAboutNotValidRules()238 virtual QString informationAboutNotValidRules() const 239 { 240 return QString(); 241 } 242 243 protected: 244 /** 245 * Helper that returns whether the rule has a negated function. 246 */ 247 bool isNegated() const; 248 249 /** 250 * Converts the rule function into the corresponding Akonadi query operator. 251 */ 252 Akonadi::SearchTerm::Condition akonadiComparator() const; 253 254 private: 255 static Function configValueToFunc(const char *); 256 static QString functionToString(Function); 257 QString conditionToString(Function function); 258 259 QByteArray mField; 260 Function mFunction; 261 QString mContents; 262 }; 263 } 264 265