summaryrefslogtreecommitdiffstats
path: root/kmail/kmsearchpattern.h
blob: bb9a9600d0bc6826b638d1bdbeb780186b7c38c6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
// -*- mode: C++; c-file-style: "gnu" -*-
// kmsearchpattern.h
// Author: Marc Mutz <Marc@Mutz.com>
// This code is under GPL!

#ifndef _kmsearchpattern_h_
#define _kmsearchpattern_h_

#include <klocale.h>
#include <qptrlist.h>
#include <qstring.h>
#include <qcstring.h>
#include "kmmsgbase.h" // for KMMsgStatus

class KMMessage;
class KConfig;
class DwBoyerMoore;
class DwString;


// maximum number of filter rules per filter
const int FILTER_MAX_RULES=8;

/** Incoming mail is sent through the list of mail filter
    rules before it is placed in the associated mail folder (usually "inbox").
    This class represents one mail filter rule. It is also used to represent
    a search rule as used by the search dialog and folders.

    @short This class represents one search pattern rule.
*/
class KMSearchRule
{
public:
  /** Operators for comparison of field and contents.
      If you change the order or contents of the enum: do not forget
      to change funcConfigNames[], sFilterFuncList and matches()
      in KMSearchRule, too.
      Also, it is assumed that these functions come in pairs of logical
      opposites (ie. "=" <-> "!=", ">" <-> "<=", etc.).
  */
  enum Function { FuncNone = -1,
                  FuncContains=0, FuncContainsNot,
		  FuncEquals, FuncNotEqual,
		  FuncRegExp, FuncNotRegExp,
		  FuncIsGreater, FuncIsLessOrEqual,
  		  FuncIsLess, FuncIsGreaterOrEqual,
		  FuncIsInAddressbook, FuncIsNotInAddressbook,
                  FuncIsInCategory, FuncIsNotInCategory,
		  FuncHasAttachment, FuncHasNoAttachment};
  KMSearchRule ( const QCString & field=0, Function=FuncContains,
                 const QString &contents=QString::null );
  KMSearchRule ( const KMSearchRule &other );

  const KMSearchRule & operator=( const KMSearchRule & other );

  /** Create a search rule of a certain type by instantiating the appro-
      priate subclass depending on the @p field. */
  static KMSearchRule* createInstance( const QCString & field=0,
                                      Function function=FuncContains,
		                      const QString & contents=QString::null );

  static KMSearchRule* createInstance( const QCString & field,
                                       const char * function,
                                       const QString & contents );

  static KMSearchRule * createInstance( const KMSearchRule & other );

  /** Initialize the object from a given config file. The group must
      be preset. @p aIdx is an identifier that is used to distinguish
      rules within a single config group. This function does no
      validation of the data obtained from the config file. You should
      call isEmpty yourself if you need valid rules. */
  static KMSearchRule* createInstanceFromConfig( const KConfig * config, int aIdx );

  virtual ~KMSearchRule() {};

  /** Tries to match the rule against the given KMMessage.
      @return TRUE if the rule matched, FALSE otherwise. Must be
      implemented by subclasses.
  */
  virtual bool matches( const KMMessage * msg ) const = 0;

   /** Optimized version tries to match the rule against the given
       @see DwString.
       @return TRUE if the rule matched, FALSE otherwise.
   */
   virtual bool matches( const DwString & str, KMMessage & msg,
                         const DwBoyerMoore * headerField=0,
                         int headerLen=-1 ) const;

  /** Determine whether the rule is worth considering. It isn't if
      either the field is not set or the contents is empty.
      KFilter should make sure that it's rule list contains
      only non-empty rules, as matches doesn't check this. */
  virtual bool isEmpty() const = 0;

  /** Returns true if the rule depends on a complete message,
      otherwise returns false. */
  virtual bool requiresBody() const { return true; }


  /** Save the object into a given config file. The group must be
      preset. @p aIdx is an identifier that is used to distinguish
      rules within a single config group. This function will happily
      write itself even when it's not valid, assuming higher layers to
      Do The Right Thing(TM). */
  void writeConfig( KConfig * config, int aIdx ) const;

  /** Return filter function. This can be any of the operators
      defined in Function. */
  Function function() const { return mFunction; }

  /** Set filter function. */
  void setFunction( Function aFunction ) { mFunction = aFunction; }

  /** Return message header field name (without the trailing ':').
      There are also six pseudo-headers:
      @li \<message\>: Try to match against the whole message.
      @li \<body\>: Try to match against the body of the message.
      @li \<any header\>: Try to match against any header field.
      @li \<recipients\>: Try to match against both To: and Cc: header fields.
      @li \<size\>: Try to match against size of message (numerical).
      @li \<age in days\>: Try to match against age of message (numerical).
      @li \<status\>: Try to match against status of message (status).
  */
  QCString field() const { return mField; }

  /** Set message header field name (make sure there's no trailing
      colon ':') */
  void setField( const QCString & field ) { mField = field; }

  /** Return the value. This can be either a substring to search for in
      or a regexp pattern to match against the header. */
  QString contents() const { return mContents; }
  /** Set the value. */
  void setContents( const QString & aContents ) { mContents = aContents; }

  /** Returns the rule as string. For debugging.*/
  const QString asString() const;

private:
  static Function configValueToFunc( const char * str );
  static QString functionToString( Function function );

  QCString mField;
  Function mFunction;
  QString  mContents;
};


// subclasses representing the different kinds of searches

/** This class represents a search to be performed against a string.
 *  The string can be either a message header, or a pseudo header, such
 *  as \<body\>
    @short This class represents a search pattern rule operating on a string.
*/

class KMSearchRuleString : public KMSearchRule
{
public:
  KMSearchRuleString( const QCString & field=0, Function function=FuncContains,
		const QString & contents=QString::null );
  KMSearchRuleString( const KMSearchRuleString & other );
  const KMSearchRuleString & operator=( const KMSearchRuleString & other );

  virtual ~KMSearchRuleString();
  virtual bool isEmpty() const ;
  virtual bool requiresBody() const;

  virtual bool matches( const KMMessage * msg ) const;

  /** Optimized version tries to match the rule against the given  DwString.
      @return TRUE if the rule matched, FALSE otherwise.
  */
  virtual bool matches( const DwString & str, KMMessage & msg,
                        const DwBoyerMoore * headerField=0,
                        int headerLen=-1 ) const;

  /** Helper for the main matches() method. Does the actual comparing. */
  bool matchesInternal( const QString & msgContents ) const;

private:
  const DwBoyerMoore *mBmHeaderField;
};


/** This class represents a search to be performed against a numerical value,
 *  such as the age of the message in days or its size.
    @short This class represents a search pattern rule operating on numerical
    values.
*/

class KMSearchRuleNumerical : public KMSearchRule
{
public:
  KMSearchRuleNumerical( const QCString & field=0, Function function=FuncContains,
		         const QString & contents=QString::null );
  virtual bool isEmpty() const ;

  virtual bool matches( const KMMessage * msg ) const;

  /** Helper for the main matches() method. Does the actual comparing. */
  bool matchesInternal( long numericalValue, long numericalMsgContents,
                        const QString & msgContents ) const;
};


namespace KMail {
// The below are used in several places and here so they are accessible.
  struct MessageStatus {
    const char * const text;
    const char * const icon;
  };

  // If you change the ordering here; also do it in the enum below
  static const MessageStatus StatusValues[] = {
    { I18N_NOOP( "Important" ),        "kmmsgflag"   },
    { I18N_NOOP( "New" ),              "kmmsgnew"   },
    { I18N_NOOP( "Unread" ),           "kmmsgunseen"   },
    { I18N_NOOP( "Read" ),             "kmmsgread"   },
    { I18N_NOOP( "Old" ),              0   },
    { I18N_NOOP( "Deleted" ),          "kmmsgdel"   },
    { I18N_NOOP( "Replied" ),          "kmmsgreplied"   },
    { I18N_NOOP( "Forwarded" ),        "kmmsgforwarded"   },
    { I18N_NOOP( "Queued" ),           "kmmsgqueued"   },
    { I18N_NOOP( "Sent" ),             "kmmsgsent"   },
    { I18N_NOOP( "Watched" ),          "kmmsgwatched"   },
    { I18N_NOOP( "Ignored" ),          "kmmsgignored"   },
    { I18N_NOOP( "Spam" ),             "kmmsgspam"   },
    { I18N_NOOP( "Ham" ),              "kmmsgham"   },
    { I18N_NOOP( "To Do" ),            "kmmsgtodo"   },
    { I18N_NOOP( "Has Attachment"),    "kmmsgattachment"   }
  };
  // If you change the ordering here; also do it in the array above
  enum StatusValueTypes {
    StatusImportant = 0,
    StatusNew = 1,
    StatusUnread = 2,
    StatusRead = 3,
    StatusOld = 4,
    StatusDeleted = 5,
    StatusReplied = 6,
    StatusForwarded = 7,
    StatusQueued = 8,
    StatusSent = 9,
    StatusWatched = 10,
    StatusIgnored = 11,
    StatusSpam = 12,
    StatusHam = 13,
    StatusToDo = 14,
    StatusHasAttachment = 15
  };

  static const int StatusValueCount =
    sizeof( StatusValues ) / sizeof( MessageStatus );
  // we want to show all status entries in the quick search bar, but only the
  // ones up to attachment in the search/filter dialog, because there the
  // attachment case is handled separately.
  static const int StatusValueCountWithoutHidden = StatusValueCount - 1;
}

/** This class represents a search to be performed against the status of a
 *  messsage. The status is represented by a bitfield.
    @short This class represents a search pattern rule operating on message
    status.
*/
class KMSearchRuleStatus : public KMSearchRule
{
public:
   KMSearchRuleStatus( const QCString & field=0, Function function=FuncContains,
		       const QString & contents=QString::null );
   KMSearchRuleStatus( int status, Function function=FuncContains );

  virtual bool isEmpty() const ;
  virtual bool matches( const KMMessage * msg ) const;
  //Not possible to implement this form for status searching
  virtual bool matches( const DwString &, KMMessage &,
                        const DwBoyerMoore *,
			int ) const;
  static KMMsgStatus statusFromEnglishName(const QString&);
  private:
  KMMsgStatus mStatus;
};

// ------------------------------------------------------------------------

/** This class is an abstraction of a search over messages.  It is
    intended to be used inside a KFilter (which adds KFilterAction's),
    as well as in KMSearch. It can read and write itself into a
    KConfig group and there is a constructor, mainly used by KMFilter
    to initialize from a preset KConfig-Group.

    From a class hierarchy point of view, it is a QPtrList of 
    KMSearchRule's that adds the boolean operators (see Operator)
    'and' and 'or' that connect the rules logically, and has a name
    under which it could be stored in the config file.

    As a QPtrList with autoDelete enabled, it assumes that it is the
    central repository for the rules it contains. So if you want to
    reuse a rule in another pattern, make a deep copy of that rule.

    @short An abstraction of a search over messages.
    @author Marc Mutz <Marc@Mutz.com>
*/
class KMSearchPattern : public QPtrList<KMSearchRule>
{

public:
  /** Boolean operators that connect the return values of the
      individual rules. A pattern with @p OpAnd will match iff all
      it's rules match, whereas a pattern with @p OpOr will match iff
      any of it's rules matches.
  */
  enum Operator { OpAnd, OpOr };
  /** Constructor that initializes from a given KConfig group, if
      given. This feature is mainly (solely?) used in KMFilter,
      as we don't allow to store search patterns in the config (yet).
      If config is 0, provides a pattern with minimal, but
      sufficient initialization. Unmodified, such a pattern will fail
      to match any KMMessage. You can query for such an empty
      rule by using isEmpty, which is inherited from QPtrList.
  */
  KMSearchPattern( const KConfig * config=0 );

  /** Destructor. Deletes all stored rules! */
  ~KMSearchPattern();

  /** The central function of this class. Tries to match the set of
      rules against a KMMessage. It's virtual to allow derived
      classes with added rules to reimplement it, yet reimplemented
      methods should and (&&) the result of this function with their
      own result or else most functionality is lacking, or has to be
      reimplemented, since the rules are private to this class.

      @return TRUE if the match was successful, FALSE otherwise.
  */
  bool matches( const KMMessage * msg, bool ignoreBody = false ) const;
  bool matches( const DwString & str, bool ignoreBody = false ) const;
  bool matches( Q_UINT32 sernum, bool ignoreBody = false ) const;

  /** Returns true if the pattern only depends the DwString that backs
      a message */
  bool requiresBody() const;

  /** Removes all empty rules from the list. You should call this
      method whenever the user had had control of the rules outside of
      this class. (e.g. after editing it with KMSearchPatternEdit).
  */
  void purify();

  /** Reads a search pattern from a KConfig.  The group has to be
      preset. If it does not find a valid saerch pattern in the preset
      group, initializes the pattern as if it were constructed using
      the default constructor.

      For backwards compatibility with previous versions of KMail, it
      checks for old-style filter rules (e.g. using @p OpIgnore)
      in @p config und converts them to the new format on writeConfig.

      Derived classes reimplementing readConfig() should also call this
      method, or else the rules will not be loaded.
  */
  void readConfig( const KConfig * config );
  /** Writes itself into @p config. The group has to be preset. Tries
      to delete old-style keys by overwriting them with QString::null.

      Derived classes reimplementing writeConfig() should also call this
      method, or else the rules will not be stored.
  */
  void writeConfig( KConfig * config ) const;

  /** Get the name of the search pattern. */
  QString name() const { return mName; }
  /** Set the name of the search pattern. KMFilter uses this to
      store it's own name, too. */
  void setName( const QString & newName ) { mName = newName ; }

  /** Get the filter operator */
  KMSearchPattern::Operator op() const { return mOperator; }
  /** Set the filter operator */
  void setOp( KMSearchPattern::Operator aOp ) { mOperator = aOp; }

  /** Returns the pattern as string. For debugging.*/
  QString asString() const;

  /** Overloaded assignment operator. Makes a deep copy. */
  const KMSearchPattern & operator=( const KMSearchPattern & aPattern );

private:
  /** Tries to import a legacy search pattern, ie. one that still has
      e.g. the @p unless or @p ignore operator which were useful as
      long as the number of rules was restricted to two. This method
      is called from readConfig, which detects legacy configurations
      and also makes sure that this method is called from an initialized
      object.
  */
  void importLegacyConfig( const KConfig * config );
  /** Initializes the object. Clears the list of rules, sets the name
      to "<i18n("unnamed")>", and the boolean operator to @p OpAnd. */
  void init();

  QString  mName;
  Operator mOperator;
};

#endif /* _kmsearchpattern_h_ */