File indexing completed on 2024-06-09 05:18:13

0001 /*
0002 
0003   SPDX-FileCopyrightText: Marc Mutz <mutz@kde.org>
0004 
0005   SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 #pragma once
0009 
0010 #include "mailcommon/searchrule.h"
0011 #include "mailcommon_export.h"
0012 #include <KLocalizedString>
0013 
0014 #include <QList>
0015 #include <QString>
0016 
0017 #include <Akonadi/SearchQuery>
0018 
0019 namespace Akonadi
0020 {
0021 class Item;
0022 }
0023 
0024 namespace KMime
0025 {
0026 class Message;
0027 }
0028 
0029 class KConfigGroup;
0030 
0031 namespace MailCommon
0032 {
0033 // ------------------------------------------------------------------------
0034 
0035 /** This class is an abstraction of a search over messages.  It is
0036     intended to be used inside a KFilter (which adds KFilterAction's),
0037     as well as in KMSearch. It can read and write itself into a
0038     KConfig group and there is a constructor, mainly used by KMFilter
0039     to initialize from a preset KConfig-Group.
0040 
0041     From a class hierarchy point of view, it is a QPtrList of
0042     SearchRule's that adds the boolean operators (see Operator)
0043     'and' and 'or' that connect the rules logically, and has a name
0044     under which it could be stored in the config file.
0045 
0046     As a QPtrList with autoDelete enabled, it assumes that it is the
0047     central repository for the rules it contains. So if you want to
0048     reuse a rule in another pattern, make a deep copy of that rule.
0049 
0050     @short An abstraction of a search over messages.
0051     @author Marc Mutz <mutz@kde.org>
0052 */
0053 class MAILCOMMON_EXPORT SearchPattern : public QList<SearchRule::Ptr>
0054 {
0055 public:
0056     /**
0057      * Boolean operators that connect the return values of the
0058      * individual rules. A pattern with @p OpAnd will match iff all
0059      *  it's rules match, whereas a pattern with @p OpOr will match if
0060      *  any of it's rules matches.
0061      */
0062     enum Operator {
0063         OpAnd,
0064         OpOr,
0065         OpAll,
0066     };
0067 
0068     enum SparqlQueryError {
0069         NoError = 0,
0070         MissingCheck,
0071         FolderEmptyOrNotIndexed,
0072         EmptyResult,
0073         NotEnoughCharacters,
0074     };
0075 
0076     /**
0077      * Constructor which provides a pattern with minimal, but
0078      * sufficient initialization. Unmodified, such a pattern will fail
0079      * to match any KMime::Message. You can query for such an empty
0080      * rule by using isEmpty, which is inherited from QPtrList.
0081      */
0082     SearchPattern();
0083 
0084     /**
0085      * Constructor that initializes from a given KConfig group, if
0086      * given. This feature is mainly (solely?) used in KMFilter,
0087      * as we don't allow to store search patterns in the config (yet).
0088      */
0089     explicit SearchPattern(const KConfigGroup &config);
0090 
0091     /** Destructor. Deletes all stored rules! */
0092     ~SearchPattern();
0093 
0094     /**
0095      * The central function of this class. Tries to match the set of
0096      * rules against a KMime::Message. It's virtual to allow derived
0097      * classes with added rules to reimplement it, yet reimplemented
0098      * methods should and (&&) the result of this function with their
0099      * own result or else most functionality is lacking, or has to be
0100      * reimplemented, since the rules are private to this class.
0101      *
0102      * @return true if the match was successful, false otherwise.
0103      */
0104     bool matches(const Akonadi::Item &item, bool ignoreBody = false) const;
0105 
0106     /**
0107      * Returns the required part from the item that is needed for the search to
0108      * operate. See @ref SearchRule::RequiredPart */
0109     SearchRule::RequiredPart requiredPart() const;
0110 
0111     /**
0112      * Removes all empty rules from the list. You should call this
0113      * method whenever the user had had control of the rules outside of
0114      * this class. (e.g. after editing it with SearchPatternEdit).
0115      */
0116     QString purify(bool removeAction = true);
0117 
0118     /**
0119      * Reads a search pattern from a KConfigGroup. If it does not find
0120      * a valid saerch pattern in the preset group, initializes the pattern
0121      * as if it were constructed using the default constructor.
0122      *
0123      * For backwards compatibility with previous versions of KMail, it
0124      * checks for old-style filter rules (e.g. using @p OpIgnore)
0125      * in @p config und converts them to the new format on writeConfig.
0126      *
0127      * Derived classes reimplementing readConfig() should also call this
0128      * method, or else the rules will not be loaded.
0129      */
0130     void readConfig(const KConfigGroup &config);
0131 
0132     /**
0133      * Writes itself into @p config. Tries to delete old-style keys by
0134      * overwriting them with QString().
0135      *
0136      * Derived classes reimplementing writeConfig() should also call this
0137      * method, or else the rules will not be stored.
0138      */
0139     void writeConfig(KConfigGroup &config) const;
0140 
0141     /**
0142      * Returns the name of the search pattern.
0143      */
0144     QString name() const
0145     {
0146         return mName;
0147     }
0148 
0149     /**
0150      * Sets the name of the search pattern. KMFilter uses this to
0151      * store it's own name, too.
0152      */
0153     void setName(const QString &newName)
0154     {
0155         mName = newName;
0156     }
0157 
0158     /**
0159      * Returns the filter operator.
0160      */
0161     SearchPattern::Operator op() const
0162     {
0163         return mOperator;
0164     }
0165 
0166     /**
0167      * Sets the filter operator.
0168      */
0169     void setOp(SearchPattern::Operator aOp)
0170     {
0171         mOperator = aOp;
0172     }
0173 
0174     static int filterRulesMaximumSize();
0175     /**
0176      * Returns the pattern as string. For debugging.
0177      */
0178     QString asString() const;
0179 
0180     /**
0181      * Returns the pattern as akonadi query
0182      */
0183     SparqlQueryError asAkonadiQuery(Akonadi::SearchQuery &) const;
0184 
0185     /**
0186      * Overloaded assignment operator. Makes a deep copy.
0187      */
0188     const SearchPattern &operator=(const SearchPattern &aPattern);
0189 
0190     /**
0191      * Writes the pattern into a byte array for persistence purposes.
0192      */
0193     QByteArray serialize() const;
0194 
0195     /**
0196      * Constructs the pattern from a byte array serialization.
0197      */
0198     void deserialize(const QByteArray &);
0199 
0200     QDataStream &operator>>(QDataStream &s) const;
0201     QDataStream &operator<<(QDataStream &s);
0202 
0203     void generateSieveScript(QStringList &requiresModules, QString &code);
0204 
0205 private:
0206     /**
0207      * Tries to import a legacy search pattern, ie. one that still has
0208      * e.g. the @p unless or @p ignore operator which were useful as long as
0209      * the number of rules was restricted to two. This method is called from
0210      * readConfig, which detects legacy configurations and also makes sure
0211      * that this method is called from an initialized object.
0212      */
0213     MAILCOMMON_NO_EXPORT void importLegacyConfig(const KConfigGroup &config);
0214 
0215     /**
0216      * Initializes the object. Clears the list of rules, sets the name
0217      * to "<i18n("unnamed")>", and the boolean operator to @p OpAnd.
0218      */
0219     void init();
0220     QString mName;
0221     Operator mOperator;
0222 };
0223 }
0224 
0225 Q_DECLARE_METATYPE(MailCommon::SearchRule::RequiredPart)