• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdepim API Reference
  • KDE Home
  • Contact Us
 

mailcommon

  • sources
  • kde-4.14
  • kdepim
  • mailcommon
  • search
searchpattern.cpp
Go to the documentation of this file.
1 /* -*- mode: C++; c-file-style: "gnu" -*-
2 
3  Author: Marc Mutz <mutz@kde.org>
4  Copyright (C) 2012 Andras Mantia <amantia@kde.org>
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License along
17  with this program; if not, write to the Free Software Foundation, Inc.,
18  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 */
20 
21 #include "searchpattern.h"
22 #include "searchrule/searchrulenumerical.h"
23 #include "searchrule/searchruledate.h"
24 #include "searchrule/searchrulestring.h"
25 #include "searchrule/searchrulestatus.h"
26 #include "filterlog.h"
27 using MailCommon::FilterLog;
28 
29 #include <Akonadi/Contact/ContactSearchJob>
30 
31 #include <Akonadi/SearchQuery>
32 
33 #include <KMime/KMimeMessage>
34 
35 #include <KPIMUtils/Email>
36 
37 //note: lowercase include for compatibility
38 #include <kascii.h>
39 #include <KDebug>
40 #include <KConfigGroup>
41 #include <KLocale>
42 #include <KGlobal>
43 
44 #include <QDataStream>
45 #include <QRegExp>
46 #include <QXmlStreamWriter>
47 
48 #include <algorithm>
49 #ifndef Q_MOC_RUN
50 #include <boost/bind.hpp>
51 #endif
52 
53 
54 
55 
56 
57 using namespace MailCommon;
58 
59 // ----------------------------------------------------------------------------
60 
61 //==================================================
62 //
63 // class SearchPattern
64 //
65 //==================================================
66 
67 SearchPattern::SearchPattern()
68  : QList<SearchRule::Ptr>()
69 {
70  init();
71 }
72 
73 SearchPattern::SearchPattern( const KConfigGroup &config )
74  : QList<SearchRule::Ptr>()
75 {
76  readConfig( config );
77 }
78 
79 SearchPattern::~SearchPattern()
80 {
81 }
82 
83 bool SearchPattern::matches( const Akonadi::Item &item, bool ignoreBody ) const
84 {
85  if ( isEmpty() ) {
86  return true;
87  }
88  if ( !item.hasPayload<KMime::Message::Ptr>() ) {
89  return false;
90  }
91 
92  QList<SearchRule::Ptr>::const_iterator it;
93  QList<SearchRule::Ptr>::const_iterator end( constEnd() );
94  switch ( mOperator ) {
95  case OpAnd: // all rules must match
96  for ( it = constBegin(); it != end; ++it ) {
97  if ( !( (*it)->requiredPart() == SearchRule::CompleteMessage && ignoreBody ) ) {
98  if ( !(*it)->matches( item ) ) {
99  return false;
100  }
101  }
102  }
103  return true;
104 
105  case OpOr: // at least one rule must match
106  for ( it = constBegin(); it != end; ++it ) {
107  if ( !( (*it)->requiredPart() == MailCommon::SearchRule::CompleteMessage && ignoreBody ) ) {
108  if ( (*it)->matches( item ) ) {
109  return true;
110  }
111  }
112  }
113  return false;
114 
115  case OpAll:
116  return true;
117 
118  default:
119  return false;
120  }
121 }
122 
123 SearchRule::RequiredPart SearchPattern::requiredPart() const
124 {
125  SearchRule::RequiredPart reqPart = SearchRule::Envelope;
126 
127  if (!isEmpty()) {
128  reqPart = (*std::max_element(constBegin(), constEnd(),
129  boost::bind(&MailCommon::SearchRule::requiredPart, _1) <
130  boost::bind(&MailCommon::SearchRule::requiredPart, _2) ))->requiredPart();
131  }
132  return reqPart;
133 }
134 
135 
136 QString SearchPattern::purify(bool removeAction)
137 {
138  QString informationAboutNotValidPattern;
139  QList<SearchRule::Ptr>::iterator it = end();
140  while ( it != begin() ) {
141  --it;
142  if ( (*it)->isEmpty() ) {
143  if (removeAction) {
144 #ifndef NDEBUG
145  kDebug() << "Removing" << (*it)->asString();
146 #endif
147  if (!informationAboutNotValidPattern.isEmpty()) {
148  informationAboutNotValidPattern += QLatin1Char('\n');
149  }
150  informationAboutNotValidPattern += (*it)->informationAboutNotValidRules();
151 
152  erase( it );
153  it = end();
154  }
155  }
156  }
157 
158  return informationAboutNotValidPattern;
159 }
160 
161 void SearchPattern::readConfig( const KConfigGroup &config )
162 {
163  init();
164 
165  mName = config.readEntry( "name" );
166  if ( !config.hasKey( "rules" ) ) {
167  kDebug() << "Found legacy config! Converting.";
168  importLegacyConfig( config );
169  return;
170  }
171 
172  const QString op = config.readEntry( "operator" );
173  if ( op == QLatin1String( "or" ) ) {
174  mOperator = OpOr;
175  } else if ( op == QLatin1String( "and" ) ) {
176  mOperator = OpAnd;
177  } else if ( op == QLatin1String( "all" ) ) {
178  mOperator = OpAll;
179  }
180 
181  const int nRules = config.readEntry( "rules", 0 );
182 
183  for ( int i = 0; i < nRules; ++i ) {
184  SearchRule::Ptr r = SearchRule::createInstanceFromConfig( config, i );
185  if ( !r->isEmpty() ) {
186  append( r );
187  }
188  }
189 }
190 
191 void SearchPattern::importLegacyConfig( const KConfigGroup & config )
192 {
193  SearchRule::Ptr rule =
194  SearchRule::createInstance(
195  config.readEntry( "fieldA" ).toLatin1(),
196  config.readEntry( "funcA" ).toLatin1(),
197  config.readEntry( "contentsA" ) );
198 
199  if ( rule->isEmpty() ) {
200  // if the first rule is invalid,
201  // we really can't do much heuristics...
202  return;
203  }
204  append( rule );
205 
206  const QString sOperator = config.readEntry( "operator" );
207  if ( sOperator == "ignore" ) {
208  return;
209  }
210 
211  rule =
212  SearchRule::createInstance(
213  config.readEntry( "fieldB" ).toLatin1(),
214  config.readEntry( "funcB" ).toLatin1(),
215  config.readEntry( "contentsB" ) );
216 
217  if ( rule->isEmpty() ) {
218  return;
219  }
220  append( rule );
221 
222  if ( sOperator == QLatin1String( "or" ) ) {
223  mOperator = OpOr;
224  return;
225  }
226  // This is the interesting case...
227  if ( sOperator == QLatin1String( "unless" ) ) { // meaning "and not", ie we need to...
228  // ...invert the function (e.g. "equals" <-> "doesn't equal")
229  // We simply toggle the last bit (xor with 0x1)... This assumes that
230  // SearchRule::Function's come in adjacent pairs of pros and cons
231  SearchRule::Function func = last()->function();
232  unsigned int intFunc = (unsigned int)func;
233  func = SearchRule::Function( intFunc ^ 0x1 );
234 
235  last()->setFunction( func );
236  }
237 
238  // treat any other case as "and" (our default).
239 }
240 
241 void SearchPattern::writeConfig( KConfigGroup &config ) const
242 {
243  config.writeEntry( "name", mName );
244  switch( mOperator ) {
245  case OpOr:
246  config.writeEntry( "operator", "or" );
247  break;
248  case OpAnd:
249  config.writeEntry( "operator", "and" );
250  break;
251  case OpAll:
252  config.writeEntry( "operator", "all" );
253  break;
254  }
255 
256  int i = 0;
257  QList<SearchRule::Ptr>::const_iterator it;
258  QList<SearchRule::Ptr>::const_iterator endIt( constEnd() );
259 
260  for ( it = constBegin(); it != endIt && i < FILTER_MAX_RULES; ++i, ++it ) {
261  // we could do this ourselves, but we want the rules to be extensible,
262  // so we give the rule it's number and let it do the rest.
263  (*it)->writeConfig( config, i );
264  }
265 
266  // save the total number of rules.
267  config.writeEntry( "rules", i );
268 }
269 
270 void SearchPattern::init()
271 {
272  clear();
273  mOperator = OpAnd;
274  mName = '<' + i18nc( "name used for a virgin filter", "unknown" ) + '>';
275 }
276 
277 QString SearchPattern::asString() const
278 {
279  QString result;
280  switch( mOperator ) {
281  case OpOr:
282  result = i18n( "(match any of the following)" );
283  break;
284  case OpAnd:
285  result = i18n( "(match all of the following)" );
286  break;
287  case OpAll:
288  result = i18n( "(match all messages)" );
289  break;
290  }
291 
292  QList<SearchRule::Ptr>::const_iterator it;
293  QList<SearchRule::Ptr>::const_iterator endIt = constEnd();
294  for ( it = constBegin(); it != endIt; ++it ) {
295  result += "\n\t" + FilterLog::recode( (*it)->asString() );
296  }
297 
298  return result;
299 }
300 
301 SearchPattern::SparqlQueryError SearchPattern::asAkonadiQuery( Akonadi::SearchQuery& query ) const
302 {
303  query = Akonadi::SearchQuery();
304 
305  Akonadi::SearchTerm term(Akonadi::SearchTerm::RelAnd);
306  if ( op() == SearchPattern::OpOr ) {
307  term = Akonadi::SearchTerm(Akonadi::SearchTerm::RelOr);
308  }
309 
310  const_iterator end( constEnd() );
311  bool emptyIsNotAnError = false;
312  bool resultAddQuery = false;
313  for ( const_iterator it = constBegin(); it != end; ++it ) {
314  (*it)->addQueryTerms( term, emptyIsNotAnError );
315  resultAddQuery &= emptyIsNotAnError;
316  }
317 
318  if ( term.subTerms().isEmpty() ) {
319  if (resultAddQuery) {
320  qDebug()<<" innergroup is Empty. Need to report bug";
321  return MissingCheck;
322  } else {
323  return EmptyResult;
324  }
325  }
326  query.setTerm(term);
327 
328  return NoError;
329 }
330 
331 const SearchPattern & SearchPattern::operator=( const SearchPattern &other )
332 {
333  if ( this == &other ) {
334  return *this;
335  }
336 
337  setOp( other.op() );
338  setName( other.name() );
339 
340  clear(); // ###
341  QList<SearchRule::Ptr>::const_iterator it;
342  QList<SearchRule::Ptr>::const_iterator end( other.constEnd() );
343  for ( it = other.constBegin(); it != end; ++it ) {
344  append( SearchRule::createInstance( **it ) ); // deep copy
345  }
346 
347  return *this;
348 }
349 
350 QByteArray SearchPattern::serialize() const
351 {
352  QByteArray out;
353  QDataStream stream( &out, QIODevice::WriteOnly );
354  *this >> stream;
355  return out;
356 }
357 
358 void SearchPattern::deserialize( const QByteArray &str )
359 {
360  QDataStream stream( str );
361  *this << stream;
362 }
363 
364 QDataStream & SearchPattern::operator>>( QDataStream &s ) const
365 {
366  switch( op() ) {
367  case SearchPattern::OpAnd:
368  s << QString::fromLatin1( "and" );
369  break;
370  case SearchPattern::OpOr:
371  s << QString::fromLatin1( "or" );
372  break;
373  case SearchPattern::OpAll:
374  s << QString::fromLatin1( "all" );
375  break;
376  }
377 
378  Q_FOREACH ( const SearchRule::Ptr rule, *this ) {
379  *rule >> s;
380  }
381  return s;
382 }
383 
384 QDataStream &SearchPattern::operator<<( QDataStream &s )
385 {
386  QString op;
387  s >> op;
388  if ( op == QLatin1String( "and" ) ) {
389  setOp( OpAnd );
390  } else if ( op == QLatin1String( "or" ) ) {
391  setOp( OpOr );
392  } else if ( op == QLatin1String( "all" ) ) {
393  setOp( OpAll );
394  }
395 
396  while ( !s.atEnd() ) {
397  SearchRule::Ptr rule = SearchRule::createInstance( s );
398  append( rule );
399  }
400  return s;
401 }
402 
403 void SearchPattern::generateSieveScript(QStringList &requires, QString &code)
404 {
405  code += QLatin1String("\n#") + mName + QLatin1Char('\n');
406  switch( mOperator ) {
407  case OpOr:
408  code += QLatin1String("if anyof (");
409  break;
410  case OpAnd:
411  code += QLatin1String("if allof (");
412  break;
413  case OpAll:
414  code += QLatin1String("if (true) {");
415  return;
416  }
417 
418  QList<SearchRule::Ptr>::const_iterator it;
419  QList<SearchRule::Ptr>::const_iterator endIt( constEnd() );
420  int i = 0;
421  for ( it = constBegin(); it != endIt && i < FILTER_MAX_RULES; ++i, ++it ) {
422  if (i != 0) {
423  code += QLatin1String("\n, ");
424  }
425  (*it)->generateSieveScript(requires, code);
426  }
427 }
428 
429 // Needed for MSVC 2010, as it seems to not implicit cast for a pointer anymore
430 #ifdef _MSC_VER
431 namespace MailCommon {
432 uint qHash( SearchRule::Ptr sr )
433 {
434  return ::qHash( sr.get() );
435 }
436 }
437 #endif
QList< SearchRule::Ptr >::clear
void clear()
MailCommon::SearchPattern::matches
bool matches(const Akonadi::Item &item, bool ignoreBody=false) const
The central function of this class.
Definition: searchpattern.cpp:83
MailCommon::SearchPattern::asString
QString asString() const
Returns the pattern as string.
Definition: searchpattern.cpp:277
MailCommon::SearchPattern::SearchPattern
SearchPattern()
Constructor which provides a pattern with minimal, but sufficient initialization. ...
Definition: searchpattern.cpp:67
MailCommon::SearchPattern::generateSieveScript
void generateSieveScript(QStringList &requires, QString &code)
Definition: searchpattern.cpp:403
MailCommon::SearchPattern::OpAll
Definition: searchpattern.h:92
MailCommon::SearchPattern::op
SearchPattern::Operator op() const
Returns the filter operator.
Definition: searchpattern.h:189
MailCommon::SearchPattern::MissingCheck
Definition: searchpattern.h:98
MailCommon::FilterLog::recode
static QString recode(const QString &plain)
Returns an escaped version of the log which can be used in a HTML document.
Definition: filterlog.cpp:228
QByteArray
MailCommon::SearchPattern::serialize
QByteArray serialize() const
Writes the pattern into a byte array for persistance purposes.
Definition: searchpattern.cpp:350
MailCommon::SearchPattern::OpOr
Definition: searchpattern.h:91
QDataStream
MailCommon::SearchPattern::operator=
const SearchPattern & operator=(const SearchPattern &aPattern)
Overloaded assignment operator.
Definition: searchpattern.cpp:331
MailCommon::SearchPattern::readConfig
void readConfig(const KConfigGroup &config)
Reads a search pattern from a KConfigGroup.
Definition: searchpattern.cpp:161
QList< SearchRule::Ptr >::erase
iterator erase(iterator pos)
MailCommon::SearchRule::Ptr
boost::shared_ptr< SearchRule > Ptr
Defines a pointer to a search rule.
Definition: searchrule.h:44
MailCommon::SearchRule::CompleteMessage
Definition: searchrule.h:82
MailCommon::SearchPattern::~SearchPattern
~SearchPattern()
Destructor.
Definition: searchpattern.cpp:79
MailCommon::FilterLog
KMail Filter Log Collector.
Definition: filterlog.h:55
filterlog.h
MailCommon::SearchPattern::operator<<
QDataStream & operator<<(QDataStream &s)
Definition: searchpattern.cpp:384
QList< SearchRule::Ptr >::append
void append(const T &value)
MailCommon::SearchRule::Function
Function
Describes operators for comparison of field and contents.
Definition: searchrule.h:55
MailCommon::SearchRule::requiredPart
virtual SearchRule::RequiredPart requiredPart() const =0
Returns the required part from the item that is needed for the search to operate. ...
searchrulestatus.h
MailCommon::SearchRule::createInstanceFromConfig
static SearchRule::Ptr createInstanceFromConfig(const KConfigGroup &group, int index)
Creates a new search rule from a given config group.
Definition: searchrule.cpp:121
MailCommon::SearchPattern::deserialize
void deserialize(const QByteArray &)
Constructs the pattern from a byte array serialization.
Definition: searchpattern.cpp:358
QList< SearchRule::Ptr >::isEmpty
bool isEmpty() const
QString::isEmpty
bool isEmpty() const
MailCommon::SearchPattern::writeConfig
void writeConfig(KConfigGroup &config) const
Writes itself into config.
Definition: searchpattern.cpp:241
MailCommon::SearchRule::RequiredPart
RequiredPart
Definition: searchrule.h:79
QString
QList
MailCommon::SearchPattern
This class is an abstraction of a search over messages.
Definition: searchpattern.h:79
QDataStream::atEnd
bool atEnd() const
QStringList
QList< SearchRule::Ptr >::end
iterator end()
searchpattern.h
QLatin1Char
MailCommon::SearchRule
This class represents one search pattern rule.
Definition: searchrule.h:38
MailCommon::SearchRule::Envelope
Definition: searchrule.h:80
MailCommon::SearchPattern::operator>>
QDataStream & operator>>(QDataStream &s) const
Definition: searchpattern.cpp:364
MailCommon::SearchPattern::OpAnd
Definition: searchpattern.h:90
MailCommon::SearchPattern::asAkonadiQuery
SparqlQueryError asAkonadiQuery(Akonadi::SearchQuery &) const
Returns the pattern as akonadi query.
Definition: searchpattern.cpp:301
QLatin1String
QList< SearchRule::Ptr >::last
T & last()
MailCommon::SearchPattern::SparqlQueryError
SparqlQueryError
Definition: searchpattern.h:96
MailCommon::SearchPattern::setOp
void setOp(SearchPattern::Operator aOp)
Sets the filter operator.
Definition: searchpattern.h:197
QString::fromLatin1
QString fromLatin1(const char *str, int size)
MailCommon::SearchPattern::NoError
Definition: searchpattern.h:97
MailCommon::SearchPattern::EmptyResult
Definition: searchpattern.h:100
searchrulestring.h
searchrulenumerical.h
MailCommon::SearchPattern::requiredPart
SearchRule::RequiredPart requiredPart() const
Returns the required part from the item that is needed for the search to operate. ...
Definition: searchpattern.cpp:123
MailCommon::SearchPattern::purify
QString purify(bool removeAction=true)
Removes all empty rules from the list.
Definition: searchpattern.cpp:136
MailCommon::SearchRule::createInstance
static SearchRule::Ptr createInstance(const QByteArray &field=0, Function function=FuncContains, const QString &contents=QString())
Creates a new search rule of a certain type by instantiating the appropriate subclass depending on th...
Definition: searchrule.cpp:91
QList< SearchRule::Ptr >::constEnd
const_iterator constEnd() const
QList< SearchRule::Ptr >::constBegin
const_iterator constBegin() const
searchruledate.h
MailCommon::FILTER_MAX_RULES
const int FILTER_MAX_RULES
Definition: searchpattern.h:49
MailCommon::SearchPattern::setName
void setName(const QString &newName)
Sets the name of the search pattern.
Definition: searchpattern.h:181
QList< SearchRule::Ptr >::begin
iterator begin()
MailCommon::SearchPattern::name
QString name() const
Returns the name of the search pattern.
Definition: searchpattern.h:172
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:31:40 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

mailcommon

Skip menu "mailcommon"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdepim API Reference

Skip menu "kdepim API Reference"
  • akonadi_next
  • akregator
  • blogilo
  • calendarsupport
  • console
  •   kabcclient
  •   konsolekalendar
  • kaddressbook
  • kalarm
  •   lib
  • kdgantt2
  • kjots
  • kleopatra
  • kmail
  • knode
  • knotes
  • kontact
  • korgac
  • korganizer
  • ktimetracker
  • libkdepim
  • libkleo
  • libkpgp
  • mailcommon
  • messagelist
  • messageviewer
  • pimprint

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal