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

mailcommon

  • sources
  • kde-4.12
  • 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 "filterlog.h"
23 using MailCommon::FilterLog;
24 
25 #include <ontologies/nie.h>
26 #include <ontologies/nmo.h>
27 #include <ontologies/nco.h>
28 
29 #include <Nepomuk2/Tag>
30 #include <Nepomuk2/Query/Query>
31 #include <Nepomuk2/Query/AndTerm>
32 #include <Nepomuk2/Query/OrTerm>
33 #include <Nepomuk2/Query/LiteralTerm>
34 #include <Nepomuk2/Query/ResourceTerm>
35 #include <Nepomuk2/Query/NegationTerm>
36 #include <Nepomuk2/Query/ResourceTypeTerm>
37 #include <Nepomuk2/Vocabulary/PIMO>
38 #include <Soprano/Vocabulary/NAO>
39 #include <Soprano/Vocabulary/RDF>
40 #include <Nepomuk2/Vocabulary/NIE>
41 
42 #include <Akonadi/Contact/ContactSearchJob>
43 
44 #include <KMime/KMimeMessage>
45 
46 #include <KPIMUtils/Email>
47 
48 //note: lowercase include for compatibility
49 #include <kascii.h>
50 #include <KDebug>
51 #include <KConfigGroup>
52 #include <KLocale>
53 #include <KGlobal>
54 
55 #include <QDataStream>
56 #include <QRegExp>
57 #include <QXmlStreamWriter>
58 
59 #include <algorithm>
60 #include <boost/bind.hpp>
61 
62 
63 using namespace MailCommon;
64 
65 static const char *funcConfigNames[] =
66 {
67  "contains", "contains-not",
68  "equals", "not-equal",
69  "regexp", "not-regexp",
70  "greater", "less-or-equal", "less", "greater-or-equal",
71  "is-in-addressbook", "is-not-in-addressbook",
72  "is-in-category", "is-not-in-category",
73  "has-attachment", "has-no-attachment",
74  "start-with", "not-start-with",
75  "end-with", "not-end-with"
76 };
77 
78 static const int numFuncConfigNames =
79  sizeof funcConfigNames / sizeof *funcConfigNames;
80 
81 struct _statusNames {
82  const char *name;
83  Akonadi::MessageStatus status;
84 };
85 
86 static struct _statusNames statusNames[] =
87 {
88  { "Important", Akonadi::MessageStatus::statusImportant() },
89  { "Unread", Akonadi::MessageStatus::statusUnread() },
90  { "Read", Akonadi::MessageStatus::statusRead() },
91  { "Deleted", Akonadi::MessageStatus::statusDeleted() },
92  { "Replied", Akonadi::MessageStatus::statusReplied() },
93  { "Forwarded", Akonadi::MessageStatus::statusForwarded() },
94  { "Queued", Akonadi::MessageStatus::statusQueued() },
95  { "Sent", Akonadi::MessageStatus::statusSent() },
96  { "Watched", Akonadi::MessageStatus::statusWatched() },
97  { "Ignored", Akonadi::MessageStatus::statusIgnored() },
98  { "Action Item", Akonadi::MessageStatus::statusToAct() },
99  { "Spam", Akonadi::MessageStatus::statusSpam() },
100  { "Ham", Akonadi::MessageStatus::statusHam() },
101  { "Has Attachment", Akonadi::MessageStatus::statusHasAttachment() }
102 };
103 
104 static const int numStatusNames =
105  sizeof statusNames / sizeof ( struct _statusNames );
106 
107 //==================================================
108 //
109 // class SearchRule (was: KMFilterRule)
110 //
111 //==================================================
112 
113 SearchRule::SearchRule( const QByteArray &field, Function func, const QString &contents )
114  : mField( field ),
115  mFunction( func ),
116  mContents( contents )
117 {
118 }
119 
120 SearchRule::SearchRule( const SearchRule &other )
121  : mField( other.mField ),
122  mFunction( other.mFunction ),
123  mContents( other.mContents )
124 {
125 }
126 
127 const SearchRule & SearchRule::operator=( const SearchRule &other )
128 {
129  if ( this == &other ) {
130  return *this;
131  }
132 
133  mField = other.mField;
134  mFunction = other.mFunction;
135  mContents = other.mContents;
136 
137  return *this;
138 }
139 
140 SearchRule::Ptr SearchRule::createInstance( const QByteArray &field,
141  Function func,
142  const QString &contents )
143 {
144  SearchRule::Ptr ret;
145  if ( field == "<status>" ) {
146  ret = SearchRule::Ptr( new SearchRuleStatus( field, func, contents ) );
147  } else if ( field == "<age in days>" || field == "<size>" ) {
148  ret = SearchRule::Ptr( new SearchRuleNumerical( field, func, contents ) );
149  } else if ( field == "<date>" ) {
150  ret = SearchRule::Ptr( new SearchRuleDate( field, func, contents ) );
151  } else {
152  ret = SearchRule::Ptr( new SearchRuleString( field, func, contents ) );
153  }
154 
155  return ret;
156 }
157 
158 SearchRule::Ptr SearchRule::createInstance( const QByteArray &field,
159  const char *func,
160  const QString &contents )
161 {
162  return ( createInstance( field, configValueToFunc( func ), contents ) );
163 }
164 
165 SearchRule::Ptr SearchRule::createInstance( const SearchRule &other )
166 {
167  return ( createInstance( other.field(), other.function(), other.contents() ) );
168 }
169 
170 SearchRule::Ptr SearchRule::createInstanceFromConfig( const KConfigGroup &config, int aIdx )
171 {
172  const char cIdx = char( int( 'A' ) + aIdx );
173 
174  static const QString & field = KGlobal::staticQString( "field" );
175  static const QString & func = KGlobal::staticQString( "func" );
176  static const QString & contents = KGlobal::staticQString( "contents" );
177 
178  const QByteArray &field2 = config.readEntry( field + cIdx, QString() ).toLatin1();
179  Function func2 = configValueToFunc( config.readEntry( func + cIdx, QString() ).toLatin1() );
180  const QString & contents2 = config.readEntry( contents + cIdx, QString() );
181 
182  if ( field2 == "<To or Cc>" ) { // backwards compat
183  return SearchRule::createInstance( "<recipients>", func2, contents2 );
184  } else {
185  return SearchRule::createInstance( field2, func2, contents2 );
186  }
187 }
188 
189 SearchRule::Ptr SearchRule::createInstance( QDataStream &s )
190 {
191  QByteArray field;
192  s >> field;
193  QString function;
194  s >> function;
195  Function func = configValueToFunc( function.toUtf8() );
196  QString contents;
197  s >> contents;
198  return createInstance( field, func, contents );
199 }
200 
201 SearchRule::~SearchRule()
202 {
203 }
204 
205 SearchRule::Function SearchRule::configValueToFunc( const char *str )
206 {
207  if ( !str ) {
208  return FuncNone;
209  }
210 
211  for ( int i = 0; i < numFuncConfigNames; ++i ) {
212  if ( qstricmp( funcConfigNames[i], str ) == 0 ) {
213  return (Function)i;
214  }
215  }
216 
217  return FuncNone;
218 }
219 
220 QString SearchRule::functionToString( Function function )
221 {
222  if ( function != FuncNone ) {
223  return funcConfigNames[int( function )];
224  } else {
225  return "invalid";
226  }
227 }
228 
229 void SearchRule::writeConfig( KConfigGroup &config, int aIdx ) const
230 {
231  const char cIdx = char( 'A' + aIdx );
232  static const QString & field = KGlobal::staticQString( "field" );
233  static const QString & func = KGlobal::staticQString( "func" );
234  static const QString & contents = KGlobal::staticQString( "contents" );
235 
236  config.writeEntry( field + cIdx, QString(mField) );
237  config.writeEntry( func + cIdx, functionToString( mFunction ) );
238  config.writeEntry( contents + cIdx, mContents );
239 }
240 
241 QString SearchRule::conditionToString(Function function)
242 {
243  QString str;
244  switch(function) {
245  case FuncEquals:
246  str = i18n("equal");
247  break;
248  case FuncNotEqual:
249  str = i18n("not equal");
250  break;
251  case FuncIsGreater:
252  str = i18n("is greater");
253  break;
254  case FuncIsLessOrEqual:
255  str = i18n("is less or equal");
256  break;
257  case FuncIsLess:
258  str = i18n("is less");
259  break;
260  case FuncIsGreaterOrEqual:
261  str = i18n("is greater or equal");
262  break;
263  case FuncIsInAddressbook:
264  str = i18n("is in addressbook");
265  break;
266  case FuncIsNotInAddressbook:
267  str = i18n("is not in addressbook");
268  break;
269  case FuncIsInCategory:
270  str = i18n("is in category");
271  break;
272  case FuncIsNotInCategory:
273  str = i18n("is in category");
274  break;
275  case FuncHasAttachment:
276  str = i18n("has an attachment");
277  break;
278  case FuncHasNoAttachment:
279  str = i18n("has not an attachment");
280  break;
281  case FuncStartWith:
282  str = i18n("start with");
283  break;
284  case FuncNotStartWith:
285  str = i18n("not start with");
286  break;
287  case FuncEndWith:
288  str = i18n("end with");
289  break;
290  case FuncNotEndWith:
291  str = i18n("not end with");
292  break;
293  case FuncNone:
294  str = i18n("none");
295  break;
296  case FuncContains:
297  str = i18n("contains");
298  break;
299  case FuncContainsNot:
300  str = i18n("not contains");
301  break;
302  case FuncRegExp:
303  str = i18n("has regexp");
304  break;
305  case FuncNotRegExp:
306  str = i18n("not regexp");
307  break;
308  }
309  return str;
310 }
311 
312 void SearchRule::generateSieveScript(QStringList &requires, QString &code)
313 {
314  QString contentStr = mContents;
315  if (mField == "<size>") {
316  QString comparaison;
317  int offset = 0;
318  switch(mFunction) {
319  case FuncEquals:
320  comparaison = QLatin1Char('"') + i18n("size equals not supported") + QLatin1Char('"');
321  break;
322  case FuncNotEqual:
323  comparaison = QLatin1Char('"') + i18n("size not equals not supported") + QLatin1Char('"');
324  break;
325  case FuncIsGreater:
326  comparaison = QLatin1String(":over");
327  break;
328  case FuncIsLessOrEqual:
329  comparaison = QLatin1String(":under");
330  offset = 1;
331  break;
332  case FuncIsLess:
333  comparaison = QLatin1String(":under");
334  break;
335  case FuncIsGreaterOrEqual:
336  comparaison = QLatin1String(":over");
337  offset = -1;
338  break;
339  case FuncIsInAddressbook:
340  case FuncIsNotInAddressbook:
341  case FuncIsInCategory:
342  case FuncIsNotInCategory:
343  case FuncHasAttachment:
344  case FuncHasNoAttachment:
345  case FuncStartWith:
346  case FuncNotStartWith:
347  case FuncEndWith:
348  case FuncNotEndWith:
349  case FuncNone:
350  case FuncContains:
351  case FuncContainsNot:
352  case FuncRegExp:
353  case FuncNotRegExp:
354  code += QLatin1Char('"') + i18n("\"%1\" is not supported with condition \"%2\"", QLatin1String(mField), conditionToString(mFunction)) + QLatin1Char('"');
355  return;
356  }
357  code += QString::fromLatin1("size %1 %2K").arg(comparaison).arg(QString::number(mContents.toInt() + offset));
358  } else if (mField == "<status>") {
359  //TODO ?
360  code += QLatin1Char('"') + i18n("<status> not implemented/supported") + QLatin1Char('"');
361  } else if (mField == "<any header>") {
362  //TODO ?
363  code += QLatin1Char('"') + i18n("<any header> not implemented/supported") + QLatin1Char('"');
364  } else if (mField == "contents") {
365  //TODO ?
366  code += QLatin1Char('"') + i18n("<contents> not implemented/supported") + QLatin1Char('"');
367  } else if (mField == "<age in days>") {
368  //TODO ?
369  code += QLatin1Char('"') + i18n("<age in days> not implemented/supported") + QLatin1Char('"');
370  } else if (mField == "<date>") {
371  //TODO ?
372  code += QLatin1Char('"') + i18n("<date> not implemented/supported") + QLatin1Char('"');
373  } else if (mField == "<recipients>") {
374  //TODO ?
375  code += QLatin1Char('"') + i18n("<recipients> not implemented/supported") + QLatin1Char('"');
376  } else if (mField == "<tag>") {
377  code += QLatin1Char('"') + i18n("<Tag> is not supported") + QLatin1Char('"');
378  } else if (mField == "<message>") {
379  //TODO ?
380  code += i18n("<message> not implemented/supported");
381  } else if (mField == "<body>") {
382  if (!requires.contains(QLatin1String("body")))
383  requires << QLatin1String("body");
384  QString comparaison;
385  bool negative = false;
386  switch(mFunction) {
387  case FuncNone:
388  break;
389  case FuncContains:
390  comparaison = QLatin1String(":contains");
391  break;
392  case FuncContainsNot:
393  negative = true;
394  comparaison = QLatin1String(":contains");
395  break;
396  case FuncEquals:
397  comparaison = QLatin1String(":is");
398  break;
399  case FuncNotEqual:
400  comparaison = QLatin1String(":is");
401  negative = true;
402  break;
403  case FuncRegExp:
404  comparaison = QLatin1String(":regex");
405  if (!requires.contains(QLatin1String("regex")))
406  requires << QLatin1String("regex");
407  break;
408  case FuncNotRegExp:
409  if (!requires.contains(QLatin1String("regex")))
410  requires << QLatin1String("regex");
411  comparaison = QLatin1String(":regex");
412  negative = true;
413  break;
414  case FuncStartWith:
415  comparaison = QLatin1String(":regex");
416  if (!requires.contains(QLatin1String("regex")))
417  requires << QLatin1String("regex");
418  contentStr = QLatin1Char('^') + contentStr;
419  break;
420  case FuncNotStartWith:
421  comparaison = QLatin1String(":regex");
422  if (!requires.contains(QLatin1String("regex")))
423  requires << QLatin1String("regex");
424  comparaison = QLatin1String(":regex");
425  contentStr = QLatin1Char('^') + contentStr;
426  negative = true;
427  break;
428  case FuncEndWith:
429  comparaison = QLatin1String(":regex");
430  if (!requires.contains(QLatin1String("regex")))
431  requires << QLatin1String("regex");
432  comparaison = QLatin1String(":regex");
433  contentStr = contentStr + QLatin1Char('$');
434  break;
435  case FuncNotEndWith:
436  comparaison = QLatin1String(":regex");
437  if (!requires.contains(QLatin1String("regex")))
438  requires << QLatin1String("regex");
439  comparaison = QLatin1String(":regex");
440  contentStr = contentStr + QLatin1Char('$');
441  negative = true;
442  break;
443  case FuncIsGreater:
444  case FuncIsLessOrEqual:
445  case FuncIsLess:
446  case FuncIsGreaterOrEqual:
447  case FuncIsInAddressbook:
448  case FuncIsNotInAddressbook:
449  case FuncIsInCategory:
450  case FuncIsNotInCategory:
451  case FuncHasAttachment:
452  case FuncHasNoAttachment:
453  code += QLatin1Char('"') + i18n("\"%1\" is not supported with condition \"%2\"", QLatin1String(mField), conditionToString(mFunction)) + QLatin1Char('"');
454  return;
455  }
456  code += (negative ? QLatin1String("not ") : QString()) + QString::fromLatin1("body :text %1 \"%2\"").arg(comparaison).arg(contentStr);
457  } else {
458  QString comparaison;
459  bool negative = false;
460  switch(mFunction) {
461  case FuncNone:
462  break;
463  case FuncContains:
464  comparaison = QLatin1String(":contains");
465  break;
466  case FuncContainsNot:
467  negative = true;
468  comparaison = QLatin1String(":contains");
469  break;
470  case FuncEquals:
471  comparaison = QLatin1String(":is");
472  break;
473  case FuncNotEqual:
474  comparaison = QLatin1String(":is");
475  negative = true;
476  break;
477  case FuncRegExp:
478  comparaison = QLatin1String(":regex");
479  if (!requires.contains(QLatin1String("regex")))
480  requires << QLatin1String("regex");
481  break;
482  case FuncNotRegExp:
483  if (!requires.contains(QLatin1String("regex")))
484  requires << QLatin1String("regex");
485  comparaison = QLatin1String(":regex");
486  negative = true;
487  break;
488  case FuncStartWith:
489  comparaison = QLatin1String(":regex");
490  if (!requires.contains(QLatin1String("regex")))
491  requires << QLatin1String("regex");
492  contentStr = QLatin1Char('^') + contentStr;
493  break;
494  case FuncNotStartWith:
495  comparaison = QLatin1String(":regex");
496  if (!requires.contains(QLatin1String("regex")))
497  requires << QLatin1String("regex");
498  comparaison = QLatin1String(":regex");
499  contentStr = QLatin1Char('^') + contentStr;
500  negative = true;
501  break;
502  case FuncEndWith:
503  comparaison = QLatin1String(":regex");
504  if (!requires.contains(QLatin1String("regex")))
505  requires << QLatin1String("regex");
506  comparaison = QLatin1String(":regex");
507  contentStr = contentStr + QLatin1Char('$');
508  break;
509  case FuncNotEndWith:
510  comparaison = QLatin1String(":regex");
511  if (!requires.contains(QLatin1String("regex")))
512  requires << QLatin1String("regex");
513  comparaison = QLatin1String(":regex");
514  contentStr = contentStr + QLatin1Char('$');
515  negative = true;
516  break;
517 
518  case FuncIsGreater:
519  case FuncIsLessOrEqual:
520  case FuncIsLess:
521  case FuncIsGreaterOrEqual:
522  case FuncIsInAddressbook:
523  case FuncIsNotInAddressbook:
524  case FuncIsInCategory:
525  case FuncIsNotInCategory:
526  case FuncHasAttachment:
527  case FuncHasNoAttachment:
528  code += QLatin1Char('"') + i18n("\"%1\" is not supported with condition \"%2\"", QLatin1String(mField), conditionToString(mFunction)) + QLatin1Char('"');
529  return;
530  }
531  code += (negative ? QLatin1String("not ") : QString()) + QString::fromLatin1("header %1 \"%2\" \"%3\"").arg(comparaison).arg(QLatin1String(mField)).arg(contentStr);
532  }
533 }
534 
535 void SearchRule::setFunction( Function function )
536 {
537  mFunction = function;
538 }
539 
540 SearchRule::Function SearchRule::function() const
541 {
542  return mFunction;
543 }
544 
545 void SearchRule::setField( const QByteArray &field )
546 {
547  mField = field;
548 }
549 
550 QByteArray SearchRule::field() const
551 {
552  return mField;
553 }
554 
555 void SearchRule::setContents( const QString &contents )
556 {
557  mContents = contents;
558 }
559 
560 QString SearchRule::contents() const
561 {
562  return mContents;
563 }
564 
565 const QString SearchRule::asString() const
566 {
567  QString result = "\"" + mField + "\" <";
568  result += functionToString( mFunction );
569  result += "> \"" + mContents + "\"";
570 
571  return result;
572 }
573 
574 
575 Nepomuk2::Query::ComparisonTerm::Comparator SearchRule::nepomukComparator() const
576 {
577  switch ( function() ) {
578  case SearchRule::FuncContains:
579  case SearchRule::FuncContainsNot:
580  return Nepomuk2::Query::ComparisonTerm::Contains;
581 
582  case SearchRule::FuncEquals:
583  case SearchRule::FuncNotEqual:
584  return Nepomuk2::Query::ComparisonTerm::Equal;
585 
586  case SearchRule::FuncIsGreater:
587  return Nepomuk2::Query::ComparisonTerm::Greater;
588 
589  case SearchRule::FuncIsGreaterOrEqual:
590  return Nepomuk2::Query::ComparisonTerm::GreaterOrEqual;
591 
592  case SearchRule::FuncIsLess:
593  return Nepomuk2::Query::ComparisonTerm::Smaller;
594 
595  case SearchRule::FuncIsLessOrEqual:
596  return Nepomuk2::Query::ComparisonTerm::SmallerOrEqual;
597 
598  case SearchRule::FuncRegExp:
599  case SearchRule::FuncNotRegExp:
600  return Nepomuk2::Query::ComparisonTerm::Regexp;
601 
602  case SearchRule::FuncStartWith:
603  case SearchRule::FuncNotStartWith:
604  case SearchRule::FuncEndWith:
605  case SearchRule::FuncNotEndWith:
606  return Nepomuk2::Query::ComparisonTerm::Regexp;
607  default:
608  kDebug() << "Unhandled function type: " << function();
609  }
610 
611  return Nepomuk2::Query::ComparisonTerm::Equal;
612 }
613 
614 bool SearchRule::isNegated() const
615 {
616  bool negate = false;
617  switch ( function() ) {
618  case SearchRule::FuncContainsNot:
619  case SearchRule::FuncNotEqual:
620  case SearchRule::FuncNotRegExp:
621  case SearchRule::FuncHasNoAttachment:
622  case SearchRule::FuncIsNotInCategory:
623  case SearchRule::FuncIsNotInAddressbook:
624  case SearchRule::FuncNotStartWith:
625  case SearchRule::FuncNotEndWith:
626  negate = true;
627  default:
628  break;
629  }
630  return negate;
631 }
632 
633 void SearchRule::addAndNegateTerm( const Nepomuk2::Query::Term &term,
634  Nepomuk2::Query::GroupTerm &termGroup ) const
635 {
636  if ( isNegated() ) {
637  Nepomuk2::Query::NegationTerm neg;
638  neg.setSubTerm( term );
639  termGroup.addSubTerm( neg );
640  } else {
641  termGroup.addSubTerm( term );
642  }
643 }
644 
645 QDataStream &SearchRule::operator >>( QDataStream &s ) const
646 {
647  s << mField << functionToString( mFunction ) << mContents;
648  return s;
649 }
650 
651 //==================================================
652 //
653 // class SearchRuleString
654 //
655 //==================================================
656 
657 SearchRuleString::SearchRuleString( const QByteArray &field,
658  Function func,
659  const QString &contents )
660  : SearchRule( field, func, contents )
661 {
662 }
663 
664 SearchRuleString::SearchRuleString( const SearchRuleString &other )
665  : SearchRule( other )
666 {
667 }
668 
669 const SearchRuleString &SearchRuleString::operator=( const SearchRuleString &other )
670 {
671  if ( this == &other ) {
672  return *this;
673  }
674 
675  setField( other.field() );
676  setFunction( other.function() );
677  setContents( other.contents() );
678 
679  return *this;
680 }
681 
682 SearchRuleString::~SearchRuleString()
683 {
684 }
685 
686 bool SearchRuleString::isEmpty() const
687 {
688  return field().trimmed().isEmpty() || contents().isEmpty();
689 }
690 
691 SearchRule::RequiredPart SearchRuleString::requiredPart() const
692 {
693  const QByteArray f = field();
694  SearchRule::RequiredPart part = Header;
695  if ( kasciistricmp( f, "<recipients>" ) == 0 ||
696  kasciistricmp( f, "<status>" ) == 0 ||
697  kasciistricmp( f, "<tag>" ) == 0 ||
698  kasciistricmp( f, "Subject" ) == 0 ||
699  kasciistricmp( f, "From" ) == 0 ) {
700  part = Envelope;
701  } else if ( kasciistricmp( f, "<message>" ) == 0 ||
702  kasciistricmp( f, "<body>" ) == 0 ) {
703  part = CompleteMessage;
704  }
705 
706  return part;
707 }
708 
709 
710 bool SearchRuleString::matches( const Akonadi::Item &item ) const
711 {
712  const KMime::Message::Ptr msg = item.payload<KMime::Message::Ptr>();
713  Q_ASSERT( msg.get() );
714 
715  if ( isEmpty() ) {
716  return false;
717  }
718 
719  if ( !msg->hasHeader( "From" ) ) {
720  msg->parse(); // probably not parsed yet: make sure we can access all headers
721  }
722 
723  QString msgContents;
724  // Show the value used to compare the rules against in the log.
725  // Overwrite the value for complete messages and all headers!
726  bool logContents = true;
727 
728  if ( kasciistricmp( field(), "<message>" ) == 0 ) {
729  msgContents = msg->encodedContent();
730  logContents = false;
731  } else if ( kasciistricmp( field(), "<body>" ) == 0 ) {
732  msgContents = msg->body();
733  logContents = false;
734  } else if ( kasciistricmp( field(), "<any header>" ) == 0 ) {
735  msgContents = msg->head();
736  logContents = false;
737  } else if ( kasciistricmp( field(), "<recipients>" ) == 0 ) {
738  // (mmutz 2001-11-05) hack to fix "<recipients> !contains foo" to
739  // meet user's expectations. See FAQ entry in KDE 2.2.2's KMail
740  // handbook
741  if ( function() == FuncEquals || function() == FuncNotEqual ) {
742  // do we need to treat this case specially? Ie.: What shall
743  // "equality" mean for recipients.
744  return
745  matchesInternal( msg->to()->asUnicodeString() ) ||
746  matchesInternal( msg->cc()->asUnicodeString() ) ||
747  matchesInternal( msg->bcc()->asUnicodeString() ) ;
748  }
749  msgContents = msg->to()->asUnicodeString();
750  msgContents += ", " + msg->cc()->asUnicodeString();
751  msgContents += ", " + msg->bcc()->asUnicodeString();
752  } else if ( kasciistricmp( field(), "<tag>" ) == 0 ) {
753  const Nepomuk2::Resource res( item.url() );
754  foreach ( const Nepomuk2::Tag &tag, res.tags() ) {
755  msgContents += tag.label();
756  }
757  logContents = false;
758  } else {
759  // make sure to treat messages with multiple header lines for
760  // the same header correctly
761  msgContents = msg->headerByType( field() ) ?
762  msg->headerByType( field() )->asUnicodeString() :
763  "";
764  }
765 
766  if ( function() == FuncIsInAddressbook ||
767  function() == FuncIsNotInAddressbook ) {
768  // I think only the "from"-field makes sense.
769  msgContents = msg->headerByType( field() ) ?
770  msg->headerByType( field() )->asUnicodeString() :
771  "";
772 
773  if ( msgContents.isEmpty() ) {
774  return ( function() == FuncIsInAddressbook ) ? false : true;
775  }
776  }
777 
778  // these two functions need the kmmessage therefore they don't call matchesInternal
779  if ( function() == FuncHasAttachment ) {
780  return ( msg->attachments().size() > 0 );
781  }
782  if ( function() == FuncHasNoAttachment ) {
783  return ( msg->attachments().size() == 0 );
784  }
785 
786  bool rc = matchesInternal( msgContents );
787  if ( FilterLog::instance()->isLogging() ) {
788  QString msg = ( rc ? "<font color=#00FF00>1 = </font>" : "<font color=#FF0000>0 = </font>" );
789  msg += FilterLog::recode( asString() );
790  // only log headers bcause messages and bodies can be pretty large
791  if ( logContents ) {
792  msg += " (<i>" + FilterLog::recode( msgContents ) + "</i>)";
793  }
794  FilterLog::instance()->add( msg, FilterLog::RuleResult );
795  }
796  return rc;
797 }
798 
799 
800 QString SearchRule::quote( const QString &content ) const
801 {
802  //Without "" nepomuk will search a message containing each individual word
803  QString newContent;
804  switch( function() ) {
805  case SearchRule::FuncRegExp:
806  case SearchRule::FuncNotRegExp:
807  newContent = content;
808  break;
809  case SearchRule::FuncStartWith:
810  case SearchRule::FuncNotStartWith:
811  newContent = QString::fromLatin1( "^%1" ).arg( content );
812  break;
813  case SearchRule::FuncEndWith:
814  case SearchRule::FuncNotEndWith:
815  newContent = QString::fromLatin1( "%1$" ).arg( content );;
816  break;
817  case SearchRule::FuncContains:
818  case SearchRule::FuncContainsNot:
819  newContent = QString::fromLatin1( "\'%1*\'" ).arg( content );
820  break;
821  default:
822  newContent = QString::fromLatin1( "\'%1\'" ).arg( content );
823  break;
824  }
825  return newContent;
826 }
827 
828 void SearchRuleString::addPersonTerm( Nepomuk2::Query::GroupTerm &groupTerm,
829  const QUrl &field ) const
830 {
831  // TODO split contents() into address/name and adapt the query accordingly
832  const Nepomuk2::Query::ComparisonTerm valueTerm(
833  Vocabulary::NCO::emailAddress(),
834  Nepomuk2::Query::LiteralTerm( contents().toLower() ),
835  nepomukComparator() );
836 
837  const Nepomuk2::Query::ComparisonTerm addressTerm(
838  Vocabulary::NCO::hasEmailAddress(),
839  valueTerm,
840  Nepomuk2::Query::ComparisonTerm::Equal );
841 
842  const Nepomuk2::Query::ComparisonTerm personTerm(
843  field,
844  addressTerm,
845  Nepomuk2::Query::ComparisonTerm::Equal );
846 
847  groupTerm.addSubTerm( personTerm );
848 }
849 
850 void SearchRuleString::addHeaderTerm( Nepomuk2::Query::GroupTerm &groupTerm,
851  const Nepomuk2::Query::Term &field ) const
852 {
853  const Nepomuk2::Query::ComparisonTerm headerName(
854  Vocabulary::NMO::headerName(),
855  field,
856  Nepomuk2::Query::ComparisonTerm::Equal );
857 
858  const Nepomuk2::Query::ComparisonTerm headerTerm(
859  Vocabulary::NMO::headerValue(),
860  Nepomuk2::Query::LiteralTerm( quote( contents() ) ),
861  nepomukComparator() );
862 
863  groupTerm.addSubTerm( headerName );
864  groupTerm.addSubTerm( headerTerm );
865 
866 }
867 
868 void SearchRuleString::addQueryTerms(Nepomuk2::Query::GroupTerm &groupTerm , bool &emptyIsNotAnError) const
869 {
870  emptyIsNotAnError = false;
871  Nepomuk2::Query::OrTerm termGroup;
872  if ( kasciistricmp( field(), "<message>" ) == 0 ||
873  kasciistricmp( field(), "<recipients>" ) == 0 ||
874  kasciistricmp( field(), "<any header>" ) == 0 ) {
875 
876  const Nepomuk2::Query::ComparisonTerm valueTerm(
877  Vocabulary::NCO::emailAddress(),
878  Nepomuk2::Query::LiteralTerm( quote( contents() ) ),
879  nepomukComparator() );
880 
881  const Nepomuk2::Query::ComparisonTerm addressTerm(
882  Vocabulary::NCO::hasEmailAddress(),
883  valueTerm,
884  Nepomuk2::Query::ComparisonTerm::Equal );
885 
886  const Nepomuk2::Query::ComparisonTerm personTerm(
887  Vocabulary::NMO::to(),
888  addressTerm,
889  Nepomuk2::Query::ComparisonTerm::Equal );
890 
891  const Nepomuk2::Query::ComparisonTerm personTermTo(
892  Vocabulary::NMO::cc(),
893  personTerm,
894  Nepomuk2::Query::ComparisonTerm::Equal );
895 
896  const Nepomuk2::Query::ComparisonTerm personTermCC(
897  Vocabulary::NMO::bcc(),
898  personTermTo,
899  Nepomuk2::Query::ComparisonTerm::Equal );
900 
901  if ( kasciistricmp( field(), "<any header>" ) == 0 ) {
902  const Nepomuk2::Query::ComparisonTerm personTermBCC(
903  Vocabulary::NMO::from(),
904  personTermTo,
905  Nepomuk2::Query::ComparisonTerm::Equal );
906  termGroup.addSubTerm( personTermBCC );
907  } else {
908  termGroup.addSubTerm( personTermCC );
909  }
910  }
911 
912  if ( kasciistricmp( field(), "to" ) == 0 ) {
913  addPersonTerm( termGroup, Vocabulary::NMO::to() );
914  } else if ( kasciistricmp( field(), "cc" ) == 0 ) {
915  addPersonTerm( termGroup, Vocabulary::NMO::cc() );
916  } else if ( kasciistricmp( field(), "bcc" ) == 0 ) {
917  addPersonTerm( termGroup, Vocabulary::NMO::bcc() );
918  } else if ( kasciistricmp( field(), "from" ) == 0 ) {
919  addPersonTerm( termGroup, Vocabulary::NMO::from() );
920  }
921 
922  if ( kasciistricmp( field(), "subject" ) == 0 ||
923  kasciistricmp( field(), "<any header>" ) == 0 ||
924  kasciistricmp( field(), "<message>" ) == 0 ) {
925  const Nepomuk2::Query::ComparisonTerm subjectTerm(
926  Vocabulary::NMO::messageSubject(),
927  Nepomuk2::Query::LiteralTerm( quote( contents() ) ),
928  nepomukComparator() );
929  termGroup.addSubTerm( subjectTerm );
930  }
931  if ( kasciistricmp( field(), "reply-to" ) == 0 ) {
932  const Nepomuk2::Query::ComparisonTerm replyToTerm(
933  Vocabulary::NMO::messageReplyTo(),
934  Nepomuk2::Query::LiteralTerm( quote(contents() ) ),
935  nepomukComparator() );
936  termGroup.addSubTerm( replyToTerm );
937  }
938 
939  if ( kasciistricmp( field(), "list-id" ) == 0 ) {
940  addHeaderTerm( termGroup, Nepomuk2::Query::LiteralTerm( "List-Id" ) );
941  } else if ( kasciistricmp( field(), "resent-from" ) == 0 ) {
942  addHeaderTerm( termGroup, Nepomuk2::Query::LiteralTerm( "Resent-From" ) );
943  } else if ( kasciistricmp( field(), "x-loop" ) == 0 ) {
944  addHeaderTerm( termGroup, Nepomuk2::Query::LiteralTerm( "X-Loop" ) );
945  } else if ( kasciistricmp( field(), "x-mailing-list" ) == 0 ) {
946  addHeaderTerm( termGroup, Nepomuk2::Query::LiteralTerm( "X-Mailing-List" ) );
947  } else if ( kasciistricmp( field(), "x-spam-flag" ) == 0 ) {
948  addHeaderTerm( termGroup, Nepomuk2::Query::LiteralTerm( "X-Spam-Flag" ) );
949  }
950 
951  // TODO complete for other headers, generic headers
952 
953  if ( kasciistricmp( field(), "organization" ) == 0 ) {
954  addHeaderTerm( termGroup, Nepomuk2::Query::LiteralTerm( "Organization" ) );
955  }
956 
957  if ( kasciistricmp( field(), "<tag>" ) == 0 ) {
958  const Nepomuk2::Tag tag( contents() );
959  if ( tag.exists() ) {
960  addAndNegateTerm(Nepomuk2::Query::ComparisonTerm(Soprano::Vocabulary::NAO::hasTag(),Nepomuk2::Query::ResourceTerm( tag ), Nepomuk2::Query::ComparisonTerm::Equal ),groupTerm );
961  } else {
962  foreach ( const Nepomuk2::Tag &tag, Nepomuk2::Tag::allTags() ) {
963  if (tag.label() == contents()) {
964  addAndNegateTerm(Nepomuk2::Query::ComparisonTerm(Soprano::Vocabulary::NAO::hasTag(),Nepomuk2::Query::ResourceTerm( tag ), Nepomuk2::Query::ComparisonTerm::Equal ),groupTerm );
965  break;
966  }
967  }
968  }
969  }
970 
971  if ( field() == "<body>" || field() == "<message>" ) {
972  const Nepomuk2::Query::ComparisonTerm bodyTerm(
973  Vocabulary::NMO::plainTextMessageContent(),
974  Nepomuk2::Query::LiteralTerm( quote( contents() ) ),
975  nepomukComparator() );
976 
977  termGroup.addSubTerm( bodyTerm );
978 
979  const Nepomuk2::Query::ComparisonTerm attachmentBodyTerm(
980  Vocabulary::NMO::plainTextMessageContent(),
981  Nepomuk2::Query::LiteralTerm( quote( contents() ) ),
982  nepomukComparator() );
983 
984  const Nepomuk2::Query::ComparisonTerm attachmentTerm(
985  Vocabulary::NIE::isPartOf(),
986  attachmentBodyTerm,
987  Nepomuk2::Query::ComparisonTerm::Equal );
988 
989  termGroup.addSubTerm( attachmentTerm );
990  }
991 
992  if ( !termGroup.subTerms().isEmpty() ) {
993  addAndNegateTerm( termGroup, groupTerm );
994  }
995 }
996 
997 // helper, does the actual comparing
998 bool SearchRuleString::matchesInternal( const QString &msgContents ) const
999 {
1000  if( msgContents.isEmpty()) {
1001  return false;
1002  }
1003 
1004  switch ( function() ) {
1005  case SearchRule::FuncEquals:
1006  return ( QString::compare( msgContents.toLower(), contents().toLower() ) == 0 );
1007 
1008  case SearchRule::FuncNotEqual:
1009  return ( QString::compare( msgContents.toLower(), contents().toLower() ) != 0 );
1010 
1011  case SearchRule::FuncContains:
1012  return ( msgContents.contains( contents(), Qt::CaseInsensitive ) );
1013 
1014  case SearchRule::FuncContainsNot:
1015  return ( !msgContents.contains( contents(), Qt::CaseInsensitive ) );
1016 
1017  case SearchRule::FuncRegExp:
1018  {
1019  QRegExp regexp( contents(), Qt::CaseInsensitive );
1020  return ( regexp.indexIn( msgContents ) >= 0 );
1021  }
1022 
1023  case SearchRule::FuncNotRegExp:
1024  {
1025  QRegExp regexp( contents(), Qt::CaseInsensitive );
1026  return ( regexp.indexIn( msgContents ) < 0 );
1027  }
1028 
1029  case SearchRule::FuncStartWith:
1030  {
1031  return msgContents.startsWith( contents() );
1032  }
1033 
1034  case SearchRule::FuncNotStartWith:
1035  {
1036  return !msgContents.startsWith( contents() );
1037  }
1038 
1039  case SearchRule::FuncEndWith:
1040  {
1041  return msgContents.endsWith( contents() );
1042  }
1043 
1044  case SearchRule::FuncNotEndWith:
1045  {
1046  return !msgContents.endsWith( contents() );
1047  }
1048 
1049  case FuncIsGreater:
1050  return ( QString::compare( msgContents.toLower(), contents().toLower() ) > 0 );
1051 
1052  case FuncIsLessOrEqual:
1053  return ( QString::compare( msgContents.toLower(), contents().toLower() ) <= 0 );
1054 
1055  case FuncIsLess:
1056  return ( QString::compare( msgContents.toLower(), contents().toLower() ) < 0 );
1057 
1058  case FuncIsGreaterOrEqual:
1059  return ( QString::compare( msgContents.toLower(), contents().toLower() ) >= 0 );
1060 
1061  case FuncIsInAddressbook:
1062  {
1063  const QStringList addressList = KPIMUtils::splitAddressList( msgContents.toLower() );
1064  QStringList::ConstIterator end( addressList.constEnd() );
1065  for ( QStringList::ConstIterator it = addressList.constBegin(); ( it != end ); ++it ) {
1066  Akonadi::ContactSearchJob *job = new Akonadi::ContactSearchJob();
1067  job->setLimit( 1 );
1068  job->setQuery( Akonadi::ContactSearchJob::Email, KPIMUtils::extractEmailAddress( *it ).toLower() );
1069  job->exec();
1070 
1071  if ( !job->contacts().isEmpty() ) {
1072  return true;
1073  }
1074  }
1075  return false;
1076  }
1077 
1078  case FuncIsNotInAddressbook:
1079  {
1080  const QStringList addressList = KPIMUtils::splitAddressList( msgContents.toLower() );
1081  QStringList::ConstIterator end( addressList.constEnd() );
1082 
1083  for ( QStringList::ConstIterator it = addressList.constBegin(); ( it != end ); ++it ) {
1084  Akonadi::ContactSearchJob *job = new Akonadi::ContactSearchJob();
1085  job->setLimit( 1 );
1086  job->setQuery( Akonadi::ContactSearchJob::Email, KPIMUtils::extractEmailAddress( *it ).toLower() );
1087  job->exec();
1088 
1089  if ( job->contacts().isEmpty() ) {
1090  return true;
1091  }
1092  }
1093  return false;
1094  }
1095 
1096  case FuncIsInCategory:
1097  {
1098  QString category = contents();
1099  const QStringList addressList = KPIMUtils::splitAddressList( msgContents.toLower() );
1100 
1101  QStringList::ConstIterator end( addressList.constEnd() );
1102  for ( QStringList::ConstIterator it = addressList.constBegin(); it != end; ++it ) {
1103  Akonadi::ContactSearchJob *job = new Akonadi::ContactSearchJob();
1104  job->setQuery( Akonadi::ContactSearchJob::Email, KPIMUtils::extractEmailAddress( *it ).toLower() );
1105  job->exec();
1106 
1107  const KABC::Addressee::List contacts = job->contacts();
1108 
1109  foreach ( const KABC::Addressee &contact, contacts ) {
1110  if ( contact.hasCategory( category ) ) {
1111  return true;
1112  }
1113  }
1114  }
1115  return false;
1116  }
1117 
1118  case FuncIsNotInCategory:
1119  {
1120  QString category = contents();
1121  const QStringList addressList = KPIMUtils::splitAddressList( msgContents.toLower() );
1122 
1123  QStringList::ConstIterator end( addressList.constEnd() );
1124  for ( QStringList::ConstIterator it = addressList.constBegin(); it != end; ++it ) {
1125  Akonadi::ContactSearchJob *job = new Akonadi::ContactSearchJob();
1126  job->setQuery( Akonadi::ContactSearchJob::Email, KPIMUtils::extractEmailAddress( *it ).toLower() );
1127  job->exec();
1128 
1129  const KABC::Addressee::List contacts = job->contacts();
1130 
1131  foreach ( const KABC::Addressee &contact, contacts ) {
1132  if ( contact.hasCategory( category ) ) {
1133  return false;
1134  }
1135  }
1136 
1137  }
1138  return true;
1139  }
1140  default:
1141  ;
1142  }
1143 
1144  return false;
1145 }
1146 
1147 //==================================================
1148 //
1149 // class SearchRuleNumerical
1150 //
1151 //==================================================
1152 
1153 SearchRuleNumerical::SearchRuleNumerical( const QByteArray &field,
1154  Function func,
1155  const QString &contents )
1156  : SearchRule( field, func, contents )
1157 {
1158 }
1159 
1160 bool SearchRuleNumerical::isEmpty() const
1161 {
1162  bool ok = false;
1163  contents().toInt( &ok );
1164 
1165  return !ok;
1166 }
1167 
1168 bool SearchRuleNumerical::matches( const Akonadi::Item &item ) const
1169 {
1170  const KMime::Message::Ptr msg = item.payload<KMime::Message::Ptr>();
1171 
1172  QString msgContents;
1173  qint64 numericalMsgContents = 0;
1174  qint64 numericalValue = 0;
1175 
1176  if ( kasciistricmp( field(), "<size>" ) == 0 ) {
1177  numericalMsgContents = item.size();
1178  numericalValue = contents().toLongLong();
1179  msgContents.setNum( numericalMsgContents );
1180  } else if ( kasciistricmp( field(), "<age in days>" ) == 0 ) {
1181  QDateTime msgDateTime = msg->date()->dateTime().dateTime();
1182  numericalMsgContents = msgDateTime.daysTo( QDateTime::currentDateTime() );
1183  numericalValue = contents().toInt();
1184  msgContents.setNum( numericalMsgContents );
1185  }
1186  bool rc = matchesInternal( numericalValue, numericalMsgContents, msgContents );
1187  if ( FilterLog::instance()->isLogging() ) {
1188  QString msg = ( rc ? "<font color=#00FF00>1 = </font>"
1189  : "<font color=#FF0000>0 = </font>" );
1190  msg += FilterLog::recode( asString() );
1191  msg += " ( <i>" + QString::number( numericalMsgContents ) + "</i> )";
1192  FilterLog::instance()->add( msg, FilterLog::RuleResult );
1193  }
1194  return rc;
1195 }
1196 
1197 SearchRule::RequiredPart SearchRuleNumerical::requiredPart() const
1198 {
1199  return SearchRule::Envelope;
1200 }
1201 
1202 
1203 bool SearchRuleNumerical::matchesInternal( long numericalValue,
1204  long numericalMsgContents, const QString & msgContents ) const
1205 {
1206  switch ( function() ) {
1207  case SearchRule::FuncEquals:
1208  return ( numericalValue == numericalMsgContents );
1209 
1210  case SearchRule::FuncNotEqual:
1211  return ( numericalValue != numericalMsgContents );
1212 
1213  case SearchRule::FuncContains:
1214  return ( msgContents.contains( contents(), Qt::CaseInsensitive ) );
1215 
1216  case SearchRule::FuncContainsNot:
1217  return ( !msgContents.contains( contents(), Qt::CaseInsensitive ) );
1218 
1219  case SearchRule::FuncRegExp:
1220  {
1221  QRegExp regexp( contents(), Qt::CaseInsensitive );
1222  return ( regexp.indexIn( msgContents ) >= 0 );
1223  }
1224 
1225  case SearchRule::FuncNotRegExp:
1226  {
1227  QRegExp regexp( contents(), Qt::CaseInsensitive );
1228  return ( regexp.indexIn( msgContents ) < 0 );
1229  }
1230 
1231  case FuncIsGreater:
1232  return ( numericalMsgContents > numericalValue );
1233 
1234  case FuncIsLessOrEqual:
1235  return ( numericalMsgContents <= numericalValue );
1236 
1237  case FuncIsLess:
1238  return ( numericalMsgContents < numericalValue );
1239 
1240  case FuncIsGreaterOrEqual:
1241  return ( numericalMsgContents >= numericalValue );
1242 
1243  case FuncIsInAddressbook: // since email-addresses are not numerical, I settle for false here
1244  return false;
1245 
1246  case FuncIsNotInAddressbook:
1247  return false;
1248 
1249  default:
1250  ;
1251  }
1252 
1253  return false;
1254 }
1255 
1256 
1257 void SearchRuleNumerical::addQueryTerms(Nepomuk2::Query::GroupTerm &groupTerm , bool &emptyIsNotAnError) const
1258 {
1259  emptyIsNotAnError = false;
1260  if ( kasciistricmp( field(), "<size>" ) == 0 ) {
1261  const Nepomuk2::Query::ComparisonTerm sizeTerm(
1262  Vocabulary::NIE::byteSize(),
1263  Nepomuk2::Query::LiteralTerm( contents().toInt() ),
1264  nepomukComparator() );
1265  addAndNegateTerm( sizeTerm, groupTerm );
1266  } else if ( kasciistricmp( field(), "<age in days>" ) == 0 ) {
1267  QDate date = QDate::currentDate();
1268  date = date.addDays( contents().toInt() );
1269  const Nepomuk2::Query::ComparisonTerm dateTerm(
1270  Vocabulary::NMO::sentDate(),
1271  Nepomuk2::Query::LiteralTerm( date ),
1272  nepomukComparator() );
1273  addAndNegateTerm( dateTerm, groupTerm );
1274  }
1275 }
1276 
1277 //==================================================
1278 //
1279 // class SearchRuleDate
1280 //
1281 //==================================================
1282 
1283 SearchRuleDate::SearchRuleDate( const QByteArray &field,
1284  Function func,
1285  const QString &contents )
1286  : SearchRule( field, func, contents )
1287 {
1288 }
1289 
1290 bool SearchRuleDate::isEmpty() const
1291 {
1292  return !QDate::fromString( contents(), Qt::ISODate ).isValid();
1293 }
1294 
1295 bool SearchRuleDate::matches( const Akonadi::Item &item ) const
1296 {
1297  const KMime::Message::Ptr msg = item.payload<KMime::Message::Ptr>();
1298 
1299 
1300  QDate msgDate = msg->date()->dateTime().date();
1301  QDate dateValue = QDate::fromString( contents(), Qt::ISODate );
1302  bool rc = matchesInternal( dateValue, msgDate );
1303  if ( FilterLog::instance()->isLogging() ) {
1304  QString msg = ( rc ? "<font color=#00FF00>1 = </font>"
1305  : "<font color=#FF0000>0 = </font>" );
1306  msg += FilterLog::recode( asString() );
1307  msg += " ( <i>" + contents() + "</i> )"; //TODO change with locale?
1308  FilterLog::instance()->add( msg, FilterLog::RuleResult );
1309  }
1310  return rc;
1311 }
1312 
1313 bool SearchRuleDate::matchesInternal( const QDate& dateValue,
1314  const QDate& msgDate ) const
1315 {
1316  switch ( function() ) {
1317  case SearchRule::FuncEquals:
1318  return ( dateValue == msgDate );
1319 
1320  case SearchRule::FuncNotEqual:
1321  return ( dateValue != msgDate );
1322 
1323  case FuncIsGreater:
1324  return ( msgDate > dateValue );
1325 
1326  case FuncIsLessOrEqual:
1327  return ( msgDate <= dateValue );
1328 
1329  case FuncIsLess:
1330  return ( msgDate < dateValue );
1331 
1332  case FuncIsGreaterOrEqual:
1333  return ( msgDate >= dateValue );
1334 
1335  default:
1336  ;
1337  }
1338  return false;
1339 }
1340 
1341 SearchRule::RequiredPart SearchRuleDate::requiredPart() const
1342 {
1343  return SearchRule::Envelope;
1344 }
1345 
1346 
1347 
1348 void SearchRuleDate::addQueryTerms(Nepomuk2::Query::GroupTerm &groupTerm , bool &emptyIsNotAnError) const
1349 {
1350  emptyIsNotAnError = false;
1351  const QDate date = QDate::fromString( contents(), Qt::ISODate );
1352  const Nepomuk2::Query::ComparisonTerm dateTerm(
1353  Vocabulary::NMO::sentDate(),
1354  Nepomuk2::Query::LiteralTerm( date ),
1355  nepomukComparator() );
1356  addAndNegateTerm( dateTerm, groupTerm );
1357 }
1358 
1359 
1360 //==================================================
1361 //
1362 // class SearchRuleStatus
1363 //
1364 //==================================================
1365 QString englishNameForStatus( const Akonadi::MessageStatus &status )
1366 {
1367  for ( int i=0; i< numStatusNames; ++i ) {
1368  if ( statusNames[i].status == status ) {
1369  return statusNames[i].name;
1370  }
1371  }
1372  return QString();
1373 }
1374 
1375 SearchRuleStatus::SearchRuleStatus( const QByteArray &field,
1376  Function func, const QString &aContents )
1377  : SearchRule( field, func, aContents )
1378 {
1379  // the values are always in english, both from the conf file as well as
1380  // the patternedit gui
1381  mStatus = statusFromEnglishName( aContents );
1382 }
1383 
1384 SearchRuleStatus::SearchRuleStatus( Akonadi::MessageStatus status, Function func )
1385  : SearchRule( "<status>", func, englishNameForStatus( status ) )
1386 {
1387  mStatus = status;
1388 }
1389 
1390 Akonadi::MessageStatus SearchRuleStatus::statusFromEnglishName( const QString &aStatusString )
1391 {
1392  for ( int i=0; i< numStatusNames; ++i ) {
1393  if ( !aStatusString.compare( statusNames[i].name ) ) {
1394  return statusNames[i].status;
1395  }
1396  }
1397  Akonadi::MessageStatus unknown;
1398  return unknown;
1399 }
1400 
1401 bool SearchRuleStatus::isEmpty() const
1402 {
1403  return field().trimmed().isEmpty() || contents().isEmpty();
1404 }
1405 
1406 bool SearchRuleStatus::matches( const Akonadi::Item &item ) const
1407 {
1408  Akonadi::MessageStatus status;
1409  status.setStatusFromFlags( item.flags() );
1410  bool rc = false;
1411  switch ( function() ) {
1412  case FuncEquals: // fallthrough. So that "<status> 'is' 'read'" works
1413  case FuncContains:
1414  if ( status & mStatus ) {
1415  rc = true;
1416  }
1417  break;
1418  case FuncNotEqual: // fallthrough. So that "<status> 'is not' 'read'" works
1419  case FuncContainsNot:
1420  if ( ! ( status & mStatus ) ) {
1421  rc = true;
1422  }
1423  break;
1424  // FIXME what about the remaining funcs, how can they make sense for
1425  // stati?
1426  default:
1427  break;
1428  }
1429  if ( FilterLog::instance()->isLogging() ) {
1430  QString msg = ( rc ? "<font color=#00FF00>1 = </font>" : "<font color=#FF0000>0 = </font>" );
1431  msg += FilterLog::recode( asString() );
1432  FilterLog::instance()->add( msg, FilterLog::RuleResult );
1433  }
1434  return rc;
1435 }
1436 
1437 SearchRule::RequiredPart SearchRuleStatus::requiredPart() const
1438 {
1439  return SearchRule::Envelope;
1440 }
1441 
1442 void SearchRuleStatus::addTagTerm( Nepomuk2::Query::GroupTerm &groupTerm,
1443  const QString &tagId ) const
1444 {
1445  // TODO handle function() == NOT
1446  qDebug()<<" tagId"<<tagId;
1447  const Nepomuk2::Tag tag( tagId );
1448  if (tag.exists()) {
1449  qDebug()<<" tag exist !";
1450  addAndNegateTerm(
1451  Nepomuk2::Query::ComparisonTerm(
1452  Soprano::Vocabulary::NAO::hasTag(),
1453  Nepomuk2::Query::ResourceTerm( tag.uri() ),
1454  Nepomuk2::Query::ComparisonTerm::Equal ),
1455  groupTerm );
1456  }
1457 }
1458 
1459 void SearchRuleStatus::addQueryTerms(Nepomuk2::Query::GroupTerm &groupTerm , bool &emptyIsNotAnError) const
1460 {
1461  emptyIsNotAnError = true;
1462  if ( mStatus.isImportant() ) {
1463  addTagTerm( groupTerm, "important" );
1464  } else if ( mStatus.isToAct() ) {
1465  addTagTerm( groupTerm, "todo" );
1466  } else if ( mStatus.isWatched() ) {
1467  addTagTerm( groupTerm, "watched" );
1468  } else if ( mStatus.isDeleted() ) {
1469  addTagTerm( groupTerm, "deleted" );
1470  } else if ( mStatus.isSpam() ) {
1471  addTagTerm( groupTerm, "spam" );
1472  } else if ( mStatus.isReplied() ) {
1473  addTagTerm( groupTerm, "replied" );
1474  } else if ( mStatus.isIgnored() ) {
1475  addTagTerm( groupTerm, "ignored" );
1476  } else if ( mStatus.isForwarded() ) {
1477  addTagTerm( groupTerm, "forwarded" );
1478  } else if ( mStatus.isSent() ) {
1479  addTagTerm( groupTerm, "sent" );
1480  } else if ( mStatus.isQueued() ) {
1481  addTagTerm( groupTerm, "queued" );
1482  } else if ( mStatus.isHam() ) {
1483  addTagTerm( groupTerm, "ham" );
1484  } else {
1485  bool read = false;
1486  if ( function() == FuncContains || function() == FuncEquals ) {
1487  read = true;
1488  }
1489 
1490  if ( !mStatus.isRead() ) {
1491  read = !read;
1492  }
1493  groupTerm.addSubTerm(
1494  Nepomuk2::Query::ComparisonTerm(
1495  Vocabulary::NMO::isRead(),
1496  Nepomuk2::Query::LiteralTerm( read ),
1497  Nepomuk2::Query::ComparisonTerm::Equal ) );
1498 
1499  }
1500 }
1501 
1502 // ----------------------------------------------------------------------------
1503 
1504 //==================================================
1505 //
1506 // class SearchPattern
1507 //
1508 //==================================================
1509 
1510 SearchPattern::SearchPattern()
1511  : QList<SearchRule::Ptr>()
1512 {
1513  init();
1514 }
1515 
1516 SearchPattern::SearchPattern( const KConfigGroup &config )
1517  : QList<SearchRule::Ptr>()
1518 {
1519  readConfig( config );
1520 }
1521 
1522 SearchPattern::~SearchPattern()
1523 {
1524 }
1525 
1526 bool SearchPattern::matches( const Akonadi::Item &item, bool ignoreBody ) const
1527 {
1528  if ( isEmpty() ) {
1529  return true;
1530  }
1531  if ( !item.hasPayload<KMime::Message::Ptr>() ) {
1532  return false;
1533  }
1534 
1535  QList<SearchRule::Ptr>::const_iterator it;
1536  QList<SearchRule::Ptr>::const_iterator end( constEnd() );
1537  switch ( mOperator ) {
1538  case OpAnd: // all rules must match
1539  for ( it = constBegin(); it != end; ++it ) {
1540  if ( !( (*it)->requiredPart() == SearchRule::CompleteMessage && ignoreBody ) ) {
1541  if ( !(*it)->matches( item ) ) {
1542  return false;
1543  }
1544  }
1545  }
1546  return true;
1547 
1548  case OpOr: // at least one rule must match
1549  for ( it = constBegin(); it != end; ++it ) {
1550  if ( !( (*it)->requiredPart() == MailCommon::SearchRule::CompleteMessage && ignoreBody ) ) {
1551  if ( (*it)->matches( item ) ) {
1552  return true;
1553  }
1554  }
1555  }
1556  return false;
1557 
1558  case OpAll:
1559  return true;
1560 
1561  default:
1562  return false;
1563  }
1564 }
1565 
1566 SearchRule::RequiredPart SearchPattern::requiredPart() const
1567 {
1568  SearchRule::RequiredPart reqPart = SearchRule::Envelope;
1569 
1570  if (!isEmpty()) {
1571  reqPart = (*std::max_element(constBegin(), constEnd(),
1572  boost::bind(&MailCommon::SearchRule::requiredPart, _1) <
1573  boost::bind(&MailCommon::SearchRule::requiredPart, _2) ))->requiredPart();
1574  }
1575  return reqPart;
1576 }
1577 
1578 
1579 void SearchPattern::purify()
1580 {
1581  QList<SearchRule::Ptr>::iterator it = end();
1582  while ( it != begin() ) {
1583  --it;
1584  if ( (*it)->isEmpty() ) {
1585 #ifndef NDEBUG
1586  kDebug() << "Removing" << (*it)->asString();
1587 #endif
1588  erase( it );
1589  it = end();
1590  }
1591  }
1592 }
1593 
1594 void SearchPattern::readConfig( const KConfigGroup &config )
1595 {
1596  init();
1597 
1598  mName = config.readEntry( "name" );
1599  if ( !config.hasKey( "rules" ) ) {
1600  kDebug() << "Found legacy config! Converting.";
1601  importLegacyConfig( config );
1602  return;
1603  }
1604 
1605  const QString op = config.readEntry( "operator" );
1606  if ( op == QLatin1String( "or" ) ) {
1607  mOperator = OpOr;
1608  } else if ( op == QLatin1String( "and" ) ) {
1609  mOperator = OpAnd;
1610  } else if ( op == QLatin1String( "all" ) ) {
1611  mOperator = OpAll;
1612  }
1613 
1614  const int nRules = config.readEntry( "rules", 0 );
1615 
1616  for ( int i = 0; i < nRules; ++i ) {
1617  SearchRule::Ptr r = SearchRule::createInstanceFromConfig( config, i );
1618  if ( !r->isEmpty() ) {
1619  append( r );
1620  }
1621  }
1622 }
1623 
1624 void SearchPattern::importLegacyConfig( const KConfigGroup & config )
1625 {
1626  SearchRule::Ptr rule =
1627  SearchRule::createInstance(
1628  config.readEntry( "fieldA" ).toLatin1(),
1629  config.readEntry( "funcA" ).toLatin1(),
1630  config.readEntry( "contentsA" ) );
1631 
1632  if ( rule->isEmpty() ) {
1633  // if the first rule is invalid,
1634  // we really can't do much heuristics...
1635  return;
1636  }
1637  append( rule );
1638 
1639  const QString sOperator = config.readEntry( "operator" );
1640  if ( sOperator == "ignore" ) {
1641  return;
1642  }
1643 
1644  rule =
1645  SearchRule::createInstance(
1646  config.readEntry( "fieldB" ).toLatin1(),
1647  config.readEntry( "funcB" ).toLatin1(),
1648  config.readEntry( "contentsB" ) );
1649 
1650  if ( rule->isEmpty() ) {
1651  return;
1652  }
1653  append( rule );
1654 
1655  if ( sOperator == QLatin1String( "or" ) ) {
1656  mOperator = OpOr;
1657  return;
1658  }
1659  // This is the interesting case...
1660  if ( sOperator == QLatin1String( "unless" ) ) { // meaning "and not", ie we need to...
1661  // ...invert the function (e.g. "equals" <-> "doesn't equal")
1662  // We simply toggle the last bit (xor with 0x1)... This assumes that
1663  // SearchRule::Function's come in adjacent pairs of pros and cons
1664  SearchRule::Function func = last()->function();
1665  unsigned int intFunc = (unsigned int)func;
1666  func = SearchRule::Function( intFunc ^ 0x1 );
1667 
1668  last()->setFunction( func );
1669  }
1670 
1671  // treat any other case as "and" (our default).
1672 }
1673 
1674 void SearchPattern::writeConfig( KConfigGroup &config ) const
1675 {
1676  config.writeEntry( "name", mName );
1677  switch( mOperator ) {
1678  case OpOr:
1679  config.writeEntry( "operator", "or" );
1680  break;
1681  case OpAnd:
1682  config.writeEntry( "operator", "and" );
1683  break;
1684  case OpAll:
1685  config.writeEntry( "operator", "all" );
1686  break;
1687  }
1688 
1689  int i = 0;
1690  QList<SearchRule::Ptr>::const_iterator it;
1691  QList<SearchRule::Ptr>::const_iterator endIt( constEnd() );
1692 
1693  for ( it = constBegin(); it != endIt && i < FILTER_MAX_RULES; ++i, ++it ) {
1694  // we could do this ourselves, but we want the rules to be extensible,
1695  // so we give the rule it's number and let it do the rest.
1696  (*it)->writeConfig( config, i );
1697  }
1698 
1699  // save the total number of rules.
1700  config.writeEntry( "rules", i );
1701 }
1702 
1703 void SearchPattern::init()
1704 {
1705  clear();
1706  mOperator = OpAnd;
1707  mName = '<' + i18nc( "name used for a virgin filter", "unknown" ) + '>';
1708 }
1709 
1710 QString SearchPattern::asString() const
1711 {
1712  QString result;
1713  switch( mOperator ) {
1714  case OpOr:
1715  result = i18n( "(match any of the following)" );
1716  break;
1717  case OpAnd:
1718  result = i18n( "(match all of the following)" );
1719  break;
1720  case OpAll:
1721  result = i18n( "(match all messages)" );
1722  break;
1723  }
1724 
1725  QList<SearchRule::Ptr>::const_iterator it;
1726  QList<SearchRule::Ptr>::const_iterator endIt = constEnd();
1727  for ( it = constBegin(); it != endIt; ++it ) {
1728  result += "\n\t" + FilterLog::recode( (*it)->asString() );
1729  }
1730 
1731  return result;
1732 }
1733 
1734 
1735 static Nepomuk2::Query::GroupTerm makeGroupTerm( SearchPattern::Operator op )
1736 {
1737  if ( op == SearchPattern::OpOr ) {
1738  return Nepomuk2::Query::OrTerm();
1739  }
1740  return Nepomuk2::Query::AndTerm();
1741 }
1742 
1743 Nepomuk2::Query::ComparisonTerm SearchPattern::createChildTerm( const KUrl& url, bool& empty ) const
1744 {
1745  const Nepomuk2::Resource parentResource( url );
1746  if ( !parentResource.exists() ) {
1747  empty = true;
1748  return Nepomuk2::Query::ComparisonTerm();
1749  }
1750  empty = false;
1751  const Nepomuk2::Query::ComparisonTerm isChildTerm( Vocabulary::NIE::isPartOf(), Nepomuk2::Query::ResourceTerm( parentResource ) );
1752  return isChildTerm;
1753 }
1754 
1755 MailCommon::SearchPattern::SparqlQueryError SearchPattern::asSparqlQuery(QString &queryStr, const KUrl::List& urlList) const
1756 {
1757  Nepomuk2::Query::Query query;
1758 
1759  Nepomuk2::Query::AndTerm outerGroup;
1760  const Nepomuk2::Types::Class cl( Vocabulary::NMO::Email() );
1761  const Nepomuk2::Query::ResourceTypeTerm typeTerm( cl );
1762  const Nepomuk2::Query::Query::RequestProperty itemIdProperty(
1763  Akonadi::ItemSearchJob::akonadiItemIdUri(), false );
1764 
1765  Nepomuk2::Query::GroupTerm innerGroup = makeGroupTerm( mOperator );
1766  const_iterator end( constEnd() );
1767  bool emptyIsNotAnError = false;
1768  bool resultAddQuery = emptyIsNotAnError;
1769  for ( const_iterator it = constBegin(); it != end; ++it ) {
1770  (*it)->addQueryTerms( innerGroup, emptyIsNotAnError );
1771  resultAddQuery &= emptyIsNotAnError;
1772  }
1773 
1774  if ( innerGroup.subTerms().isEmpty() ) {
1775  if (resultAddQuery) {
1776  qDebug()<<" innergroup is Empty. Need to report bug";
1777  return MissingCheck;
1778  } else {
1779  return EmptyResult;
1780  }
1781  }
1782  if ( !urlList.isEmpty() ) {
1783  const int numberOfUrl = urlList.count();
1784  if ( numberOfUrl == 1 ) {
1785  bool empty = false;
1786  const Nepomuk2::Query::ComparisonTerm isChildTerm = createChildTerm( urlList.at( 0 ), empty );
1787  if ( empty ) {
1788  return FolderEmptyOrNotIndexed;
1789  }
1790  const Nepomuk2::Query::AndTerm andTerm( isChildTerm, innerGroup );
1791  outerGroup.addSubTerm( andTerm );
1792  } else {
1793  QList<Nepomuk2::Query::Term> term;
1794  bool allFolderIsEmpty = true;
1795  for ( int i = 0; i < numberOfUrl; ++i ) {
1796  bool empty = false;
1797  const Nepomuk2::Query::ComparisonTerm childTerm = createChildTerm( urlList.at( i ), empty );
1798  if ( !empty ) {
1799  term<<childTerm;
1800  allFolderIsEmpty = false;
1801  }
1802  }
1803  if (allFolderIsEmpty) {
1804  return FolderEmptyOrNotIndexed;
1805  }
1806  const Nepomuk2::Query::OrTerm orTerm( term );
1807  const Nepomuk2::Query::AndTerm andTerm( orTerm, innerGroup );
1808  outerGroup.addSubTerm( andTerm );
1809  }
1810 
1811  } else {
1812  outerGroup.addSubTerm( innerGroup );
1813  }
1814  outerGroup.addSubTerm( typeTerm );
1815  query.setTerm( outerGroup );
1816  query.addRequestProperty( itemIdProperty );
1817  queryStr = query.toSparqlQuery();
1818  return NoError;
1819 }
1820 
1821 
1822 const SearchPattern & SearchPattern::operator=( const SearchPattern &other )
1823 {
1824  if ( this == &other ) {
1825  return *this;
1826  }
1827 
1828  setOp( other.op() );
1829  setName( other.name() );
1830 
1831  clear(); // ###
1832  QList<SearchRule::Ptr>::const_iterator it;
1833  QList<SearchRule::Ptr>::const_iterator end( other.constEnd() );
1834  for ( it = other.constBegin(); it != end; ++it ) {
1835  append( SearchRule::createInstance( **it ) ); // deep copy
1836  }
1837 
1838  return *this;
1839 }
1840 
1841 QByteArray SearchPattern::serialize() const
1842 {
1843  QByteArray out;
1844  QDataStream stream( &out, QIODevice::WriteOnly );
1845  *this >> stream;
1846  return out;
1847 }
1848 
1849 void SearchPattern::deserialize( const QByteArray &str )
1850 {
1851  QDataStream stream( str );
1852  *this << stream;
1853 }
1854 
1855 QDataStream & SearchPattern::operator>>( QDataStream &s ) const
1856 {
1857  switch( op() ) {
1858  case SearchPattern::OpAnd:
1859  s << QString::fromLatin1( "and" );
1860  break;
1861  case SearchPattern::OpOr:
1862  s << QString::fromLatin1( "or" );
1863  break;
1864  case SearchPattern::OpAll:
1865  s << QString::fromLatin1( "all" );
1866  break;
1867  }
1868 
1869  Q_FOREACH ( const SearchRule::Ptr rule, *this ) {
1870  *rule >> s;
1871  }
1872  return s;
1873 }
1874 
1875 QDataStream &SearchPattern::operator<<( QDataStream &s )
1876 {
1877  QString op;
1878  s >> op;
1879  if ( op == QLatin1String( "and" ) ) {
1880  setOp( OpAnd );
1881  } else if ( op == QLatin1String( "or" ) ) {
1882  setOp( OpOr );
1883  } else if ( op == QLatin1String( "all" ) ) {
1884  setOp( OpAll );
1885  }
1886 
1887  while ( !s.atEnd() ) {
1888  SearchRule::Ptr rule = SearchRule::createInstance( s );
1889  append( rule );
1890  }
1891  return s;
1892 }
1893 
1894 void SearchPattern::generateSieveScript(QStringList &requires, QString &code)
1895 {
1896  code += QLatin1String("\n#") + mName + QLatin1Char('\n');
1897  switch( mOperator ) {
1898  case OpOr:
1899  code += QLatin1String("if anyof (");
1900  break;
1901  case OpAnd:
1902  code += QLatin1String("if allof (");
1903  break;
1904  case OpAll:
1905  code += QLatin1String("if (true) {");
1906  return;
1907  }
1908 
1909  QList<SearchRule::Ptr>::const_iterator it;
1910  QList<SearchRule::Ptr>::const_iterator endIt( constEnd() );
1911  int i = 0;
1912  for ( it = constBegin(); it != endIt && i < FILTER_MAX_RULES; ++i, ++it ) {
1913  if (i != 0) {
1914  code += QLatin1String("\n, ");
1915  }
1916  (*it)->generateSieveScript(requires, code);
1917  }
1918 }
1919 
1920 // Needed for MSVC 2010, as it seems to not implicit cast for a pointer anymore
1921 #ifdef _MSC_VER
1922 namespace MailCommon {
1923 uint qHash( SearchRule::Ptr sr )
1924 {
1925  return ::qHash( sr.get() );
1926 }
1927 }
1928 #endif
MailCommon::SearchRule::FuncIsInAddressbook
Definition: searchpattern.h:92
MailCommon::SearchPattern::matches
bool matches(const Akonadi::Item &item, bool ignoreBody=false) const
The central function of this class.
Definition: searchpattern.cpp:1526
MailCommon::SearchRuleDate::matches
virtual bool matches(const Akonadi::Item &item) const
Tries to match the rule against the KMime::Message in the given item.
Definition: searchpattern.cpp:1295
MailCommon::SearchRule::FuncEndWith
Definition: searchpattern.h:100
MailCommon::SearchPattern::asSparqlQuery
SparqlQueryError asSparqlQuery(QString &queryStr, const KUrl::List &url=KUrl::List()) const
Returns the pattern as a SPARQL query.
Definition: searchpattern.cpp:1755
MailCommon::SearchRule::operator>>
QDataStream & operator>>(QDataStream &) const
Definition: searchpattern.cpp:645
MailCommon::SearchRuleNumerical::addQueryTerms
virtual void addQueryTerms(Nepomuk2::Query::GroupTerm &groupTerm, bool &emptyIsNotAnError) const
Adds query terms to the given term group.
Definition: searchpattern.cpp:1257
MailCommon::SearchPattern::asString
QString asString() const
Returns the pattern as string.
Definition: searchpattern.cpp:1710
MailCommon::SearchPattern::SearchPattern
SearchPattern()
Constructor which provides a pattern with minimal, but sufficient initialization. ...
Definition: searchpattern.cpp:1510
MailCommon::SearchRuleString::matchesInternal
bool matchesInternal(const QString &contents) const
A helper method for the main matches() method.
Definition: searchpattern.cpp:998
MailCommon::SearchPattern::generateSieveScript
void generateSieveScript(QStringList &requires, QString &code)
Definition: searchpattern.cpp:1894
MailCommon::SearchPattern::OpAll
Definition: searchpattern.h:608
MailCommon::SearchRule::FuncIsGreaterOrEqual
Definition: searchpattern.h:91
MailCommon::SearchRule::FuncNotEndWith
Definition: searchpattern.h:101
statusNames
static struct _statusNames statusNames[]
Definition: searchpattern.cpp:86
MailCommon::SearchPattern::op
SearchPattern::Operator op() const
Returns the filter operator.
Definition: searchpattern.h:705
MailCommon::SearchRuleStatus::SearchRuleStatus
SearchRuleStatus(const QByteArray &field=0, Function function=FuncContains, const QString &contents=QString())
Definition: searchpattern.cpp:1375
MailCommon::SearchPattern::MissingCheck
Definition: searchpattern.h:614
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:227
MailCommon::SearchRuleStatus::statusFromEnglishName
static Akonadi::MessageStatus statusFromEnglishName(const QString &)
Definition: searchpattern.cpp:1390
MailCommon::SearchRule::SearchRule
SearchRule(const QByteArray &field=0, Function function=FuncContains, const QString &contents=QString())
Creates new new search rule.
Definition: searchpattern.cpp:113
MailCommon::SearchPattern::serialize
QByteArray serialize() const
Writes the pattern into a byte array for persistance purposes.
Definition: searchpattern.cpp:1841
MailCommon::SearchPattern::OpOr
Definition: searchpattern.h:607
MailCommon::SearchRule::FuncContainsNot
Definition: searchpattern.h:83
MailCommon::SearchRuleNumerical::requiredPart
virtual RequiredPart requiredPart() const
Returns the required part from the item that is needed for the search to operate. ...
Definition: searchpattern.cpp:1197
MailCommon::SearchRule::FuncIsNotInAddressbook
Definition: searchpattern.h:93
MailCommon::SearchRuleNumerical::SearchRuleNumerical
SearchRuleNumerical(const QByteArray &field=0, Function function=FuncContains, const QString &contents=QString())
Creates new numerical search rule.
Definition: searchpattern.cpp:1153
MailCommon::SearchRule::setField
void setField(const QByteArray &name)
Sets the message header field name.
Definition: searchpattern.cpp:545
MailCommon::SearchRuleDate::isEmpty
virtual bool isEmpty() const
Determines whether the rule is worth considering.
Definition: searchpattern.cpp:1290
MailCommon::SearchRule::FuncIsInCategory
Definition: searchpattern.h:94
numFuncConfigNames
static const int numFuncConfigNames
Definition: searchpattern.cpp:78
MailCommon::SearchRule::FuncNotStartWith
Definition: searchpattern.h:99
MailCommon::SearchRuleNumerical
This class represents a search pattern rule operating on numerical values.
Definition: searchpattern.h:387
MailCommon::SearchPattern::operator=
const SearchPattern & operator=(const SearchPattern &aPattern)
Overloaded assignment operator.
Definition: searchpattern.cpp:1822
MailCommon::SearchPattern::readConfig
void readConfig(const KConfigGroup &config)
Reads a search pattern from a KConfigGroup.
Definition: searchpattern.cpp:1594
MailCommon::SearchRule::writeConfig
void writeConfig(KConfigGroup &group, int index) const
Saves the object into a given config group.
Definition: searchpattern.cpp:229
MailCommon::SearchRuleNumerical::isEmpty
virtual bool isEmpty() const
Determines whether the rule is worth considering.
Definition: searchpattern.cpp:1160
MailCommon::SearchRule::FuncHasAttachment
Definition: searchpattern.h:96
MailCommon::SearchRule::quote
QString quote(const QString &content) const
Definition: searchpattern.cpp:800
MailCommon::SearchRule::Ptr
boost::shared_ptr< SearchRule > Ptr
Defines a pointer to a search rule.
Definition: searchpattern.h:69
MailCommon::SearchRule::CompleteMessage
Definition: searchpattern.h:107
MailCommon::SearchPattern::~SearchPattern
~SearchPattern()
Destructor.
Definition: searchpattern.cpp:1522
MailCommon::SearchRuleDate::matchesInternal
bool matchesInternal(const QDate &dateValue, const QDate &msgDate) const
A helper method for the main matches() method.
Definition: searchpattern.cpp:1313
MailCommon::SearchRule::setContents
void setContents(const QString &contents)
Set the contents of the rule.
Definition: searchpattern.cpp:555
MailCommon::SearchRule::setFunction
void setFunction(Function function)
Sets the filter function of the rule.
Definition: searchpattern.cpp:535
MailCommon::FilterLog::instance
static FilterLog * instance()
Returns the single global instance of the filter log.
Definition: filterlog.cpp:106
MailCommon::FilterLog
KMail Filter Log Collector.
Definition: filterlog.h:56
filterlog.h
MailCommon::SearchRuleStatus::requiredPart
virtual RequiredPart requiredPart() const
Returns the required part from the item that is needed for the search to operate. ...
Definition: searchpattern.cpp:1437
MailCommon::SearchRule::FuncStartWith
Definition: searchpattern.h:98
MailCommon::SearchRule::FuncNotRegExp
Definition: searchpattern.h:87
MailCommon::SearchRule::operator=
const SearchRule & operator=(const SearchRule &other)
Initializes this rule with an other rule.
Definition: searchpattern.cpp:127
MailCommon::SearchPattern::operator<<
QDataStream & operator<<(QDataStream &s)
Definition: searchpattern.cpp:1875
MailCommon::SearchRule::Function
Function
Describes operators for comparison of field and contents.
Definition: searchpattern.h:80
MailCommon::SearchRule::requiredPart
virtual SearchRule::RequiredPart requiredPart() const =0
Returns the required part from the item that is needed for the search to operate. ...
MailCommon::SearchRule::FuncNotEqual
Definition: searchpattern.h:85
MailCommon::SearchRule::createInstanceFromConfig
static SearchRule::Ptr createInstanceFromConfig(const KConfigGroup &group, int index)
Creates a new search rule from a given config group.
Definition: searchpattern.cpp:170
MailCommon::SearchPattern::deserialize
void deserialize(const QByteArray &)
Constructs the pattern from a byte array serialization.
Definition: searchpattern.cpp:1849
MailCommon::FilterLog::isLogging
bool isLogging() const
Returns whether the filter log is currently active.
Definition: filterlog.cpp:115
MailCommon::SearchPattern::Operator
Operator
Boolean operators that connect the return values of the individual rules.
Definition: searchpattern.h:605
MailCommon::SearchRuleString::isEmpty
virtual bool isEmpty() const
Determines whether the rule is worth considering.
Definition: searchpattern.cpp:686
MailCommon::SearchRule::asString
const QString asString() const
Returns the rule as string for debugging purpose.
Definition: searchpattern.cpp:565
funcConfigNames
static const char * funcConfigNames[]
Definition: searchpattern.cpp:65
MailCommon::SearchRule::contents
QString contents() const
Returns the contents of the rule.
Definition: searchpattern.cpp:560
MailCommon::SearchRule::~SearchRule
virtual ~SearchRule()
Destroys the search rule.
Definition: searchpattern.cpp:201
MailCommon::SearchRuleString::SearchRuleString
SearchRuleString(const QByteArray &field=0, Function function=FuncContains, const QString &contents=QString())
Creates new new string search rule.
Definition: searchpattern.cpp:657
MailCommon::SearchRuleNumerical::matches
virtual bool matches(const Akonadi::Item &item) const
Tries to match the rule against the KMime::Message in the given item.
Definition: searchpattern.cpp:1168
MailCommon::SearchRule::FuncNone
Definition: searchpattern.h:81
MailCommon::SearchPattern::writeConfig
void writeConfig(KConfigGroup &config) const
Writes itself into config.
Definition: searchpattern.cpp:1674
MailCommon::SearchRuleDate::requiredPart
virtual RequiredPart requiredPart() const
Returns the required part from the item that is needed for the search to operate. ...
Definition: searchpattern.cpp:1341
MailCommon::SearchRule::RequiredPart
RequiredPart
Definition: searchpattern.h:104
MailCommon::SearchPattern::FolderEmptyOrNotIndexed
Definition: searchpattern.h:615
MailCommon::SearchRule::FuncHasNoAttachment
Definition: searchpattern.h:97
MailCommon::SearchPattern
This class is an abstraction of a search over messages.
Definition: searchpattern.h:595
MailCommon::SearchRule::field
QByteArray field() const
Returns the message header field name (without the trailing ':').
Definition: searchpattern.cpp:550
MailCommon::SearchRule::FuncRegExp
Definition: searchpattern.h:86
MailCommon::SearchRule::isNegated
bool isNegated() const
Helper that returns whether the rule has a negated function.
Definition: searchpattern.cpp:614
MailCommon::SearchRuleStatus
This class represents a search to be performed against the status of a messsage.
Definition: searchpattern.h:543
MailCommon::SearchRuleString::requiredPart
virtual RequiredPart requiredPart() const
Returns the required part from the item that is needed for the search to operate. ...
Definition: searchpattern.cpp:691
searchpattern.h
MailCommon::SearchRule
This class represents one search pattern rule.
Definition: searchpattern.h:63
MailCommon::SearchRule::FuncIsNotInCategory
Definition: searchpattern.h:95
MailCommon::SearchRule::Envelope
Definition: searchpattern.h:105
MailCommon::SearchRule::FuncContains
Definition: searchpattern.h:82
MailCommon::SearchRule::function
Function function() const
Returns the filter function of the rule.
Definition: searchpattern.cpp:540
MailCommon::SearchPattern::operator>>
QDataStream & operator>>(QDataStream &s) const
Definition: searchpattern.cpp:1855
MailCommon::SearchPattern::OpAnd
Definition: searchpattern.h:606
numStatusNames
static const int numStatusNames
Definition: searchpattern.cpp:104
MailCommon::SearchRuleString::addQueryTerms
virtual void addQueryTerms(Nepomuk2::Query::GroupTerm &groupTerm, bool &emptyIsNotAnError) const
Adds query terms to the given term group.
Definition: searchpattern.cpp:868
MailCommon::SearchRule::generateSieveScript
void generateSieveScript(QStringList &requires, QString &code)
Definition: searchpattern.cpp:312
MailCommon::SearchRule::FuncIsGreater
Definition: searchpattern.h:88
MailCommon::SearchRuleString
This class represents a search pattern rule operating on a string.
Definition: searchpattern.h:317
MailCommon::SearchRuleString::operator=
const SearchRuleString & operator=(const SearchRuleString &other)
Initializes this rule with an other rule.
Definition: searchpattern.cpp:669
MailCommon::SearchRule::FuncIsLessOrEqual
Definition: searchpattern.h:89
MailCommon::SearchRuleDate
Definition: searchpattern.h:435
MailCommon::SearchRuleString::matches
virtual bool matches(const Akonadi::Item &item) const
Tries to match the rule against the KMime::Message in the given item.
Definition: searchpattern.cpp:710
MailCommon::SearchRuleStatus::matches
virtual bool matches(const Akonadi::Item &item) const
Tries to match the rule against the KMime::Message in the given item.
Definition: searchpattern.cpp:1406
MailCommon::SearchPattern::SparqlQueryError
SparqlQueryError
Definition: searchpattern.h:612
MailCommon::SearchPattern::setOp
void setOp(SearchPattern::Operator aOp)
Sets the filter operator.
Definition: searchpattern.h:713
MailCommon::SearchRuleStatus::isEmpty
virtual bool isEmpty() const
Determines whether the rule is worth considering.
Definition: searchpattern.cpp:1401
MailCommon::SearchPattern::NoError
Definition: searchpattern.h:613
MailCommon::SearchPattern::EmptyResult
Definition: searchpattern.h:616
MailCommon::SearchRuleStatus::addQueryTerms
virtual void addQueryTerms(Nepomuk2::Query::GroupTerm &groupTerm, bool &emptyIsNotAnError) const
Adds query terms to the given term group.
Definition: searchpattern.cpp:1459
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:1566
MailCommon::FilterLog::add
void add(const QString &entry, ContentType type)
Adds the given log entry under the given content type to the log.
Definition: filterlog.cpp:163
MailCommon::SearchRuleString::~SearchRuleString
virtual ~SearchRuleString()
Destroys the string search rule.
Definition: searchpattern.cpp:682
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: searchpattern.cpp:140
MailCommon::SearchRule::Header
Definition: searchpattern.h:106
englishNameForStatus
QString englishNameForStatus(const Akonadi::MessageStatus &status)
Definition: searchpattern.cpp:1365
MailCommon::SearchPattern::purify
void purify()
Removes all empty rules from the list.
Definition: searchpattern.cpp:1579
MailCommon::FILTER_MAX_RULES
const int FILTER_MAX_RULES
Definition: searchpattern.h:54
MailCommon::SearchRuleNumerical::matchesInternal
bool matchesInternal(long numericalValue, long numericalContents, const QString &contents) const
A helper method for the main matches() method.
Definition: searchpattern.cpp:1203
MailCommon::SearchRuleDate::addQueryTerms
virtual void addQueryTerms(Nepomuk2::Query::GroupTerm &groupTerm, bool &emptyIsNotAnError) const
Adds query terms to the given term group.
Definition: searchpattern.cpp:1348
MailCommon::SearchRule::addAndNegateTerm
void addAndNegateTerm(const Nepomuk2::Query::Term &term, Nepomuk2::Query::GroupTerm &termGroup) const
Adds term to termGroup and adds a negation term inbetween if needed.
Definition: searchpattern.cpp:633
MailCommon::SearchPattern::setName
void setName(const QString &newName)
Sets the name of the search pattern.
Definition: searchpattern.h:697
MailCommon::SearchRuleDate::SearchRuleDate
SearchRuleDate(const QByteArray &field=0, Function function=FuncContains, const QString &contents=QString())
Creates new date search rule.
Definition: searchpattern.cpp:1283
MailCommon::SearchRule::FuncIsLess
Definition: searchpattern.h:90
MailCommon::SearchRule::FuncEquals
Definition: searchpattern.h:84
makeGroupTerm
static Nepomuk2::Query::GroupTerm makeGroupTerm(SearchPattern::Operator op)
Definition: searchpattern.cpp:1735
MailCommon::SearchPattern::name
QString name() const
Returns the name of the search pattern.
Definition: searchpattern.h:688
MailCommon::SearchRule::nepomukComparator
Nepomuk2::Query::ComparisonTerm::Comparator nepomukComparator() const
Converts the rule function into the corresponding Nepomuk query operator.
Definition: searchpattern.cpp:575
MailCommon::FilterLog::RuleResult
Log all rule matching results.
Definition: filterlog.h:77
QList
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:55:15 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

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