00001
00002
00003
00004
00005
00006
#include <config.h>
00007
00008
#include "kmaddrbook.h"
00009
#include "kmsearchpattern.h"
00010
#include "kmmessage.h"
00011
#include "kmmsgindex.h"
00012
#include "kmmsgdict.h"
00013
#include "filterlog.h"
00014
using KMail::FilterLog;
00015
00016
#include <libkdepim/email.h>
00017
00018
#include <kglobal.h>
00019
#include <klocale.h>
00020
#include <kdebug.h>
00021
#include <kconfig.h>
00022
00023
#include <kabc/stdaddressbook.h>
00024
00025
#include <qregexp.h>
00026
00027
#include <mimelib/string.h>
00028
#include <mimelib/boyermor.h>
00029
00030
#include <assert.h>
00031
00032
static const char* funcConfigNames[] =
00033 {
"contains",
"contains-not",
"equals",
"not-equal",
"regexp",
00034
"not-regexp",
"greater",
"less-or-equal",
"less",
"greater-or-equal",
00035
"is-in-addressbook",
"is-not-in-addressbook" ,
"is-in-category",
"is-not-in-category",
00036
"has-attachment",
"has-no-attachment"};
00037
static const int numFuncConfigNames =
sizeof funcConfigNames /
sizeof *funcConfigNames;
00038
00039
00040
00041
00042
00043
00044
00045
00046 KMSearchRule::KMSearchRule(
const QCString & field, Function func,
const QString & contents )
00047 : mField( field ),
00048 mFunction( func ),
00049 mContents( contents )
00050 {
00051 }
00052
00053 KMSearchRule::KMSearchRule(
const KMSearchRule & other )
00054 : mField( other.mField ),
00055 mFunction( other.mFunction ),
00056 mContents( other.mContents )
00057 {
00058 }
00059
00060
const KMSearchRule & KMSearchRule::operator=(
const KMSearchRule & other ) {
00061
if (
this == &other )
00062
return *
this;
00063
00064 mField = other.
mField;
00065 mFunction = other.
mFunction;
00066 mContents = other.
mContents;
00067
00068
return *
this;
00069 }
00070
00071 KMSearchRule *
KMSearchRule::createInstance(
const QCString & field,
00072 Function func,
00073
const QString & contents )
00074 {
00075
KMSearchRule *ret;
00076
if (field ==
"<status>")
00077 ret =
new KMSearchRuleStatus( field, func, contents );
00078
else if ( field ==
"<age in days>" || field ==
"<size>" )
00079 ret =
new KMSearchRuleNumerical( field, func, contents );
00080
else
00081 ret =
new KMSearchRuleString( field, func, contents );
00082
00083
return ret;
00084 }
00085
00086
KMSearchRule * KMSearchRule::createInstance(
const QCString & field,
00087
const char *func,
00088
const QString & contents )
00089 {
00090
return ( createInstance( field, configValueToFunc( func ), contents ) );
00091 }
00092
00093
KMSearchRule *
KMSearchRule::createInstance(
const KMSearchRule & other )
00094 {
00095
return (
createInstance( other.
field(), other.
function(), other.
contents() ) );
00096 }
00097
00098 KMSearchRule *
KMSearchRule::createInstanceFromConfig(
const KConfig * config,
int aIdx )
00099 {
00100
const char cIdx = char(
int(
'A') + aIdx );
00101
00102
static const QString & field = KGlobal::staticQString(
"field" );
00103
static const QString & func = KGlobal::staticQString(
"func" );
00104
static const QString & contents = KGlobal::staticQString(
"contents" );
00105
00106
const QCString &field2 = config->readEntry( field + cIdx ).latin1();
00107
Function func2 = configValueToFunc( config->readEntry( func + cIdx ).latin1() );
00108
const QString & contents2 = config->readEntry( contents + cIdx );
00109
00110
if ( field2 ==
"<To or Cc>" )
00111
return KMSearchRule::createInstance(
"<recipients>", func2, contents2 );
00112
else
00113
return KMSearchRule::createInstance( field2, func2, contents2 );
00114 }
00115
00116 KMSearchRule::Function KMSearchRule::configValueToFunc(
const char * str ) {
00117
if ( !str )
00118
return FuncNone;
00119
00120
for (
int i = 0 ; i < numFuncConfigNames ; ++i )
00121
if ( qstricmp( funcConfigNames[i], str ) == 0 )
return (Function)i;
00122
00123
return FuncNone;
00124 }
00125
00126
QString KMSearchRule::functionToString( Function function )
00127 {
00128
if ( function != FuncNone )
00129
return funcConfigNames[int( function )];
00130
else
00131
return "invalid";
00132 }
00133
00134 void KMSearchRule::writeConfig( KConfig * config,
int aIdx )
const {
00135
const char cIdx = char(
'A' + aIdx);
00136
static const QString & field = KGlobal::staticQString(
"field" );
00137
static const QString & func = KGlobal::staticQString(
"func" );
00138
static const QString & contents = KGlobal::staticQString(
"contents" );
00139
00140 config->writeEntry( field + cIdx,
QString(mField) );
00141 config->writeEntry( func + cIdx, functionToString( mFunction ) );
00142 config->writeEntry( contents + cIdx, mContents );
00143 }
00144
00145 bool KMSearchRule::matches(
const DwString & aStr, KMMessage & msg,
00146
const DwBoyerMoore *,
int )
const
00147
{
00148
if ( !msg.isComplete() ) {
00149 msg.fromDwString( aStr );
00150 msg.setComplete(
true );
00151 }
00152
return matches( &msg );
00153 }
00154
00155 const QString KMSearchRule::asString()
const
00156
{
00157
QString result =
"\"" + mField +
"\" <";
00158 result += functionToString( mFunction );
00159 result +=
"> \"" + mContents +
"\"";
00160
00161
return result;
00162 }
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172 KMSearchRuleString::KMSearchRuleString(
const QCString & field,
00173 Function func,
const QString & contents )
00174 :
KMSearchRule(field, func, contents)
00175 {
00176
if ( field.isEmpty() || field[0] ==
'<' )
00177 mBmHeaderField = 0;
00178
else
00179 mBmHeaderField =
new DwBoyerMoore((
"\n" + field +
": ").data());
00180 }
00181
00182 KMSearchRuleString::KMSearchRuleString(
const KMSearchRuleString & other )
00183 :
KMSearchRule( other ),
00184 mBmHeaderField( 0 )
00185 {
00186
if ( other.
mBmHeaderField )
00187 mBmHeaderField =
new DwBoyerMoore( *other.
mBmHeaderField );
00188 }
00189
00190
const KMSearchRuleString & KMSearchRuleString::operator=(
const KMSearchRuleString & other )
00191 {
00192
if (
this == &other )
00193
return *
this;
00194
00195
setField( other.
field() );
00196 mBmHeaderField =
new DwBoyerMoore( *other.
mBmHeaderField );
00197
setFunction( other.
function() );
00198
setContents( other.
contents() );
00199
delete mBmHeaderField; mBmHeaderField = 0;
00200
if ( other.
mBmHeaderField )
00201 mBmHeaderField =
new DwBoyerMoore( *other.
mBmHeaderField );
00202
00203
return *
this;
00204 }
00205
00206 KMSearchRuleString::~KMSearchRuleString()
00207 {
00208
delete mBmHeaderField;
00209 mBmHeaderField = 0;
00210 }
00211
00212 bool KMSearchRuleString::isEmpty()
const
00213
{
00214
return field().stripWhiteSpace().isEmpty() ||
contents().isEmpty();
00215 }
00216
00217 bool KMSearchRuleString::requiresBody()
const
00218
{
00219
if (mBmHeaderField || (
field() ==
"<recipients>" ))
00220
return false;
00221
return true;
00222 }
00223
00224 bool KMSearchRuleString::matches(
const DwString & aStr, KMMessage & msg,
00225
const DwBoyerMoore * aHeaderField,
int aHeaderLen )
const
00226
{
00227
if (
isEmpty() )
00228
return false;
00229
00230
const DwBoyerMoore * headerField = aHeaderField ? aHeaderField : mBmHeaderField ;
00231
00232
const int headerLen = ( aHeaderLen > -1 ? aHeaderLen :
field().length() ) + 2 ;
00233
00234
if ( headerField ) {
00235
static const DwBoyerMoore lflf(
"\n\n" );
00236
static const DwBoyerMoore lfcrlf(
"\n\r\n" );
00237
00238 size_t endOfHeader = lflf.FindIn( aStr, 0 );
00239
if ( endOfHeader == DwString::npos )
00240 endOfHeader = lfcrlf.FindIn( aStr, 0 );
00241
const DwString headers = ( endOfHeader == DwString::npos ) ? aStr : aStr.substr( 0, endOfHeader );
00242 size_t start = headerField->FindIn( headers, 0,
false );
00243
00244
00245
00246
00247
if ( start == DwString::npos )
00248
return ( (
function() & 1 ) == 1 );
00249 start += headerLen;
00250 size_t stop = aStr.find(
'\n', start );
00251
char ch =
'\0';
00252
while ( stop != DwString::npos && ( ch = aStr.at( stop + 1 ) ) ==
' ' || ch ==
'\t' )
00253 stop = aStr.find(
'\n', stop + 1 );
00254
const int len = stop == DwString::npos ? aStr.length() - start : stop - start ;
00255
const QCString codedValue( aStr.data() + start, len + 1 );
00256
const QString msgContents = KMMsgBase::decodeRFC2047String( codedValue ).stripWhiteSpace();
00257
return matchesInternal( msgContents );
00258 }
else if (
field() ==
"<recipients>" ) {
00259
static const DwBoyerMoore to(
"\nTo: ");
00260
static const DwBoyerMoore cc(
"\nCc: ");
00261
static const DwBoyerMoore bcc(
"\nBcc: ");
00262
00263
00264
00265
if ( (
function() & 1 ) == 0 ) {
00266
00267
return (
matches( aStr, msg, &to, 2 ) ||
00268
matches( aStr, msg, &cc, 2 ) ||
00269
matches( aStr, msg, &bcc, 3 ) );
00270 }
00271
else {
00272
00273
return (
matches( aStr, msg, &to, 2 ) &&
00274
matches( aStr, msg, &cc, 2 ) &&
00275
matches( aStr, msg, &bcc, 3 ) );
00276 }
00277 }
00278
return false;
00279 }
00280
00281 bool KMSearchRuleString::matches(
const KMMessage * msg )
const
00282
{
00283 assert( msg );
00284
00285
if (
isEmpty() )
00286
return false;
00287
00288
QString msgContents;
00289
00290
00291
bool logContents =
true;
00292
00293
if(
field() ==
"<message>" ) {
00294 msgContents = msg->asString();
00295 logContents =
false;
00296 }
else if (
field() ==
"<body>" ) {
00297 msgContents = msg->bodyToUnicode();
00298 logContents =
false;
00299 }
else if (
field() ==
"<any header>" ) {
00300 msgContents = msg->headerAsString();
00301 logContents =
false;
00302 }
else if (
field() ==
"<recipients>" ) {
00303
00304
00305
00306
if (
function() == FuncEquals ||
function() == FuncNotEqual )
00307
00308
00309
return matchesInternal( msg->headerField(
"To") )
00310 ||
matchesInternal( msg->headerField(
"Cc") )
00311 ||
matchesInternal( msg->headerField(
"Bcc") )
00312
00313 ||
matchesInternal( msg->cc() );
00314
00315 msgContents = msg->headerField(
"To");
00316
if ( !msg->headerField(
"Cc").compare( msg->cc() ) )
00317 msgContents +=
", " + msg->headerField(
"Cc");
00318
else
00319 msgContents +=
", " + msg->cc();
00320 msgContents +=
", " + msg->headerField(
"Bcc");
00321 }
else {
00322
00323
00324 msgContents = msg->headerFields(
field() ).join(
" " );
00325 }
00326
00327
if (
function() == FuncIsInAddressbook ||
00328
function() == FuncIsNotInAddressbook ) {
00329
00330 msgContents = msg->headerField(
field() );
00331
if ( msgContents.isEmpty() )
00332
return false;
00333 }
00334
00335
00336
if (
function() == FuncHasAttachment )
00337
return ( msg->toMsgBase().attachmentState() == KMMsgHasAttachment );
00338
if (
function() == FuncHasNoAttachment )
00339
return ( ((KMMsgAttachmentState) msg->toMsgBase().attachmentState()) == KMMsgHasNoAttachment );
00340
00341
bool rc =
matchesInternal( msgContents );
00342
if (
FilterLog::instance()->
isLogging() ) {
00343
QString msg = ( rc ?
"<font color=#00FF00>1 = </font>"
00344 :
"<font color=#FF0000>0 = </font>" );
00345 msg += FilterLog::recode(
asString() );
00346
00347
if ( logContents )
00348 msg +=
" (<i>" + FilterLog::recode( msgContents ) +
"</i>)";
00349
FilterLog::instance()->
add( msg, FilterLog::ruleResult );
00350 }
00351
return rc;
00352 }
00353
00354
00355 bool KMSearchRuleString::matchesInternal(
const QString & msgContents )
const
00356
{
00357
switch (
function() ) {
00358
case KMSearchRule::FuncEquals:
00359
return ( QString::compare( msgContents.lower(),
contents().lower() ) == 0 );
00360
00361
case KMSearchRule::FuncNotEqual:
00362
return ( QString::compare( msgContents.lower(),
contents().lower() ) != 0 );
00363
00364
case KMSearchRule::FuncContains:
00365
return ( msgContents.find(
contents(), 0,
false ) >= 0 );
00366
00367
case KMSearchRule::FuncContainsNot:
00368
return ( msgContents.find(
contents(), 0,
false ) < 0 );
00369
00370
case KMSearchRule::FuncRegExp:
00371 {
00372
QRegExp regexp(
contents(),
false );
00373
return ( regexp.search( msgContents ) >= 0 );
00374 }
00375
00376
case KMSearchRule::FuncNotRegExp:
00377 {
00378
QRegExp regexp(
contents(),
false );
00379
return ( regexp.search( msgContents ) < 0 );
00380 }
00381
00382
case FuncIsGreater:
00383
return ( QString::compare( msgContents.lower(),
contents().lower() ) > 0 );
00384
00385
case FuncIsLessOrEqual:
00386
return ( QString::compare( msgContents.lower(),
contents().lower() ) <= 0 );
00387
00388
case FuncIsLess:
00389
return ( QString::compare( msgContents.lower(),
contents().lower() ) < 0 );
00390
00391
case FuncIsGreaterOrEqual:
00392
return ( QString::compare( msgContents.lower(),
contents().lower() ) >= 0 );
00393
00394
case FuncIsInAddressbook: {
00395 KABC::AddressBook *stdAb = KABC::StdAddressBook::self();
00396
QStringList addressList =
00397 KPIM::splitEmailAddrList( msgContents.lower() );
00398
for( QStringList::ConstIterator it = addressList.begin();
00399 ( it != addressList.end() );
00400 ++it ) {
00401
if ( !stdAb->findByEmail( KPIM::getEmailAddr( *it ) ).isEmpty() )
00402
return true;
00403 }
00404
return false;
00405 }
00406
00407
case FuncIsNotInAddressbook: {
00408 KABC::AddressBook *stdAb = KABC::StdAddressBook::self();
00409
QStringList addressList =
00410 KPIM::splitEmailAddrList( msgContents.lower() );
00411
for( QStringList::ConstIterator it = addressList.begin();
00412 ( it != addressList.end() );
00413 ++it ) {
00414
if ( stdAb->findByEmail( KPIM::getEmailAddr( *it ) ).isEmpty() )
00415
return true;
00416 }
00417
return false;
00418 }
00419
00420
case FuncIsInCategory: {
00421
QString category =
contents();
00422
QStringList addressList = KPIM::splitEmailAddrList( msgContents.lower() );
00423 KABC::AddressBook *stdAb = KABC::StdAddressBook::self();
00424
00425
for( QStringList::ConstIterator it = addressList.begin();
00426 it != addressList.end(); ++it ) {
00427 KABC::Addressee::List addresses = stdAb->findByEmail( KPIM::getEmailAddr( *it ) );
00428
00429
for ( KABC::Addressee::List::Iterator itAd = addresses.begin(); itAd != addresses.end(); ++itAd )
00430
if ( (*itAd).hasCategory(category) )
00431
return true;
00432
00433 }
00434
return false;
00435 }
00436
00437
case FuncIsNotInCategory: {
00438
QString category =
contents();
00439
QStringList addressList = KPIM::splitEmailAddrList( msgContents.lower() );
00440 KABC::AddressBook *stdAb = KABC::StdAddressBook::self();
00441
00442
for( QStringList::ConstIterator it = addressList.begin();
00443 it != addressList.end(); ++it ) {
00444 KABC::Addressee::List addresses = stdAb->findByEmail( KPIM::getEmailAddr( *it ) );
00445
00446
for ( KABC::Addressee::List::Iterator itAd = addresses.begin(); itAd != addresses.end(); ++itAd )
00447
if ( (*itAd).hasCategory(category) )
00448
return false;
00449
00450 }
00451
return true;
00452 }
00453
default:
00454 ;
00455 }
00456
00457
return false;
00458 }
00459
00460
00461
00462
00463
00464
00465
00466
00467 KMSearchRuleNumerical::KMSearchRuleNumerical(
const QCString & field,
00468 Function func,
const QString & contents )
00469 :
KMSearchRule(field, func, contents)
00470 {
00471 }
00472
00473 bool KMSearchRuleNumerical::isEmpty()
const
00474
{
00475
bool ok =
false;
00476
contents().toInt( &ok );
00477
00478
return !ok;
00479 }
00480
00481
00482 bool KMSearchRuleNumerical::matches(
const KMMessage * msg )
const
00483
{
00484
00485
QString msgContents;
00486
int numericalMsgContents = 0;
00487
int numericalValue = 0;
00488
00489
if (
field() ==
"<size>" ) {
00490 numericalMsgContents = int( msg->msgLength() );
00491 numericalValue =
contents().toInt();
00492 msgContents.setNum( numericalMsgContents );
00493 }
else if (
field() ==
"<age in days>" ) {
00494
QDateTime msgDateTime;
00495 msgDateTime.setTime_t( msg->date() );
00496 numericalMsgContents = msgDateTime.daysTo( QDateTime::currentDateTime() );
00497 numericalValue =
contents().toInt();
00498 msgContents.setNum( numericalMsgContents );
00499 }
00500
bool rc =
matchesInternal( numericalValue, numericalMsgContents, msgContents );
00501
if (
FilterLog::instance()->
isLogging() ) {
00502
QString msg = ( rc ?
"<font color=#00FF00>1 = </font>"
00503 :
"<font color=#FF0000>0 = </font>" );
00504 msg += FilterLog::recode(
asString() );
00505 msg +=
" ( <i>" + QString::number( numericalMsgContents ) +
"</i> )";
00506
FilterLog::instance()->
add( msg, FilterLog::ruleResult );
00507 }
00508
return rc;
00509 }
00510
00511 bool KMSearchRuleNumerical::matchesInternal(
long numericalValue,
00512
long numericalMsgContents,
const QString & msgContents )
const
00513
{
00514
switch (
function() ) {
00515
case KMSearchRule::FuncEquals:
00516
return ( numericalValue == numericalMsgContents );
00517
00518
case KMSearchRule::FuncNotEqual:
00519
return ( numericalValue != numericalMsgContents );
00520
00521
case KMSearchRule::FuncContains:
00522
return ( msgContents.find(
contents(), 0,
false ) >= 0 );
00523
00524
case KMSearchRule::FuncContainsNot:
00525
return ( msgContents.find(
contents(), 0,
false ) < 0 );
00526
00527
case KMSearchRule::FuncRegExp:
00528 {
00529
QRegExp regexp(
contents(),
false );
00530
return ( regexp.search( msgContents ) >= 0 );
00531 }
00532
00533
case KMSearchRule::FuncNotRegExp:
00534 {
00535
QRegExp regexp(
contents(),
false );
00536
return ( regexp.search( msgContents ) < 0 );
00537 }
00538
00539
case FuncIsGreater:
00540
return ( numericalMsgContents > numericalValue );
00541
00542
case FuncIsLessOrEqual:
00543
return ( numericalMsgContents <= numericalValue );
00544
00545
case FuncIsLess:
00546
return ( numericalMsgContents < numericalValue );
00547
00548
case FuncIsGreaterOrEqual:
00549
return ( numericalMsgContents >= numericalValue );
00550
00551
case FuncIsInAddressbook:
00552
return false;
00553
00554
case FuncIsNotInAddressbook:
00555
return false;
00556
00557
default:
00558 ;
00559 }
00560
00561
return false;
00562 }
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573 KMSearchRuleStatus::KMSearchRuleStatus(
const QCString & field,
00574 Function func,
const QString & aContents )
00575 :
KMSearchRule(field, func, aContents)
00576 {
00577
00578
00579 mStatus = statusFromEnglishName( aContents );
00580 }
00581
00582 KMMsgStatus KMSearchRuleStatus::statusFromEnglishName(
00583
const QString & aStatusString )
00584 {
00585 KMMsgStatus status = 0;
00586
if ( ! aStatusString.compare(
"important") )
00587 status = KMMsgStatusFlag;
00588
if ( ! aStatusString.compare(
"new") )
00589 status = KMMsgStatusNew;
00590
if ( ! aStatusString.compare(
"unread") )
00591 status = KMMsgStatusUnread | KMMsgStatusNew;
00592
if ( ! aStatusString.compare(
"read") )
00593 status = KMMsgStatusRead;
00594
if ( ! aStatusString.compare(
"old") )
00595 status = KMMsgStatusOld;
00596
if ( ! aStatusString.compare(
"deleted") )
00597 status = KMMsgStatusDeleted;
00598
if ( ! aStatusString.compare(
"replied") )
00599 status = KMMsgStatusReplied;
00600
if ( ! aStatusString.compare(
"forwarded") )
00601 status = KMMsgStatusForwarded;
00602
if ( ! aStatusString.compare(
"queued") )
00603 status = KMMsgStatusQueued;
00604
if ( ! aStatusString.compare(
"sent") )
00605 status = KMMsgStatusSent;
00606
if ( ! aStatusString.compare(
"watched") )
00607 status = KMMsgStatusWatched;
00608
if ( ! aStatusString.compare(
"ignored") )
00609 status = KMMsgStatusIgnored;
00610
if ( ! aStatusString.compare(
"todo") )
00611 status = KMMsgStatusTodo;
00612
if ( ! aStatusString.compare(
"spam") )
00613 status = KMMsgStatusSpam;
00614
if ( ! aStatusString.compare(
"ham") )
00615 status = KMMsgStatusHam;
00616
if ( ! aStatusString.compare(
"has an attachment") )
00617 status = KMMsgStatusHasAttach;
00618
00619
return status;
00620 }
00621
00622
bool KMSearchRuleStatus::isEmpty()
const
00623
{
00624
return field().stripWhiteSpace().isEmpty() ||
contents().isEmpty();
00625 }
00626
00627
bool KMSearchRuleStatus::matches(
const DwString &, KMMessage &,
00628
const DwBoyerMoore *,
int )
const
00629
{
00630 assert( 0 );
00631
return false;
00632 }
00633
00634
bool KMSearchRuleStatus::matches(
const KMMessage * msg )
const
00635
{
00636
00637 KMMsgStatus msgStatus = msg->status();
00638
bool rc =
false;
00639
00640
switch (
function() ) {
00641
case FuncEquals:
00642
case FuncContains:
00643
if (msgStatus & mStatus)
00644 rc =
true;
00645
break;
00646
case FuncNotEqual:
00647
case FuncContainsNot:
00648
if (! (msgStatus & mStatus) )
00649 rc =
true;
00650
break;
00651
00652
00653
default:
00654
break;
00655 }
00656
00657
if (
FilterLog::instance()->
isLogging() ) {
00658
QString msg = ( rc ?
"<font color=#00FF00>1 = </font>"
00659 :
"<font color=#FF0000>0 = </font>" );
00660 msg += FilterLog::recode(
asString() );
00661
FilterLog::instance()->
add( msg, FilterLog::ruleResult );
00662 }
00663
return rc;
00664 }
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674 KMSearchPattern::KMSearchPattern(
const KConfig * config )
00675 :
QPtrList<
KMSearchRule>()
00676 {
00677 setAutoDelete(
true );
00678
if ( config )
00679
readConfig( config );
00680
else
00681 init();
00682 }
00683
00684 KMSearchPattern::~KMSearchPattern()
00685 {
00686 }
00687
00688 bool KMSearchPattern::matches(
const KMMessage * msg )
const
00689
{
00690
if ( isEmpty() )
00691
return true;
00692
00693
QPtrListIterator<KMSearchRule> it( *
this );
00694
switch ( mOperator ) {
00695
case OpAnd:
00696
for ( it.toFirst() ; it.current() ; ++it )
00697
if ( !(*it)->matches( msg ) )
00698
return false;
00699
return true;
00700
case OpOr:
00701
for ( it.toFirst() ; it.current() ; ++it )
00702
if ( (*it)->matches( msg ) )
00703
return true;
00704
00705
default:
00706
return false;
00707 }
00708 }
00709
00710
bool KMSearchPattern::matches(
const DwString & aStr )
const
00711
{
00712
if ( isEmpty() )
00713
return true;
00714
00715 KMMessage msg;
00716
QPtrListIterator<KMSearchRule> it( *
this );
00717
switch ( mOperator ) {
00718
case OpAnd:
00719
for ( it.toFirst() ; it.current() ; ++it )
00720
if ( !(*it)->matches( aStr, msg ) )
00721
return false;
00722
return true;
00723
case OpOr:
00724
for ( it.toFirst() ; it.current() ; ++it )
00725
if ( (*it)->matches( aStr, msg ) )
00726
return true;
00727
00728
default:
00729
return false;
00730 }
00731 }
00732
00733
bool KMSearchPattern::matches( Q_UINT32 serNum )
const
00734
{
00735
if ( isEmpty() )
00736
return true;
00737
00738
bool res;
00739
int idx = -1;
00740
KMFolder *folder = 0;
00741 kmkernel->msgDict()->getLocation(serNum, &folder, &idx);
00742
if (!folder || (idx == -1) || (idx >= folder->
count())) {
00743
return false;
00744 }
00745
00746
bool opened = folder->
isOpened();
00747
if ( !opened )
00748 folder->
open();
00749 KMMsgBase *msgBase = folder->
getMsgBase(idx);
00750
if (
requiresBody()) {
00751
bool unGet = !msgBase->isMessage();
00752 KMMessage *msg = folder->
getMsg(idx);
00753 res =
matches( msg );
00754
if (unGet)
00755 folder->
unGetMsg(idx);
00756 }
else {
00757 res =
matches( folder->
getDwString(idx) );
00758 }
00759
if ( !opened )
00760 folder->
close();
00761
return res;
00762 }
00763
00764 bool KMSearchPattern::requiresBody()
const {
00765
QPtrListIterator<KMSearchRule> it( *
this );
00766
for ( it.toFirst() ; it.current() ; ++it )
00767
if ( (*it)->requiresBody() )
00768
return true;
00769
return false;
00770 }
00771
00772 void KMSearchPattern::purify() {
00773
QPtrListIterator<KMSearchRule> it( *
this );
00774 it.toLast();
00775
while ( it.current() )
00776
if ( (*it)->isEmpty() ) {
00777
#ifndef NDEBUG
00778
kdDebug(5006) <<
"KMSearchPattern::purify(): removing " << (*it)->asString() << endl;
00779
#endif
00780
remove( *it );
00781 }
else {
00782 --it;
00783 }
00784 }
00785
00786 void KMSearchPattern::readConfig(
const KConfig * config ) {
00787 init();
00788
00789 mName = config->readEntry(
"name");
00790
if ( !config->hasKey(
"rules") ) {
00791 kdDebug(5006) <<
"KMSearchPattern::readConfig: found legacy config! Converting." << endl;
00792 importLegacyConfig( config );
00793
return;
00794 }
00795
00796 mOperator = config->readEntry(
"operator") ==
"or" ? OpOr : OpAnd;
00797
00798
const int nRules = config->readNumEntry(
"rules", 0 );
00799
00800
for (
int i = 0 ; i < nRules ; i++ ) {
00801
KMSearchRule * r = KMSearchRule::createInstanceFromConfig( config, i );
00802
if ( r->
isEmpty() )
00803
delete r;
00804
else
00805 append( r );
00806 }
00807 }
00808
00809
void KMSearchPattern::importLegacyConfig(
const KConfig * config ) {
00810
KMSearchRule * rule = KMSearchRule::createInstance( config->readEntry(
"fieldA").latin1(),
00811 config->readEntry(
"funcA").latin1(),
00812 config->readEntry(
"contentsA") );
00813
if ( rule->
isEmpty() ) {
00814
00815
00816
delete rule;
00817
return;
00818 }
00819 append( rule );
00820
00821
const QString sOperator = config->readEntry(
"operator");
00822
if ( sOperator ==
"ignore" )
return;
00823
00824 rule =
KMSearchRule::createInstance( config->readEntry(
"fieldB").latin1(),
00825 config->readEntry(
"funcB").latin1(),
00826 config->readEntry(
"contentsB") );
00827
if ( rule->
isEmpty() ) {
00828
delete rule;
00829
return;
00830 }
00831 append( rule );
00832
00833
if ( sOperator ==
"or" ) {
00834 mOperator = OpOr;
00835
return;
00836 }
00837
00838
if ( sOperator ==
"unless" ) {
00839
00840
00841
00842
KMSearchRule::Function func = last()->function();
00843
unsigned int intFunc = (
unsigned int)func;
00844 func =
KMSearchRule::Function( intFunc ^ 0x1 );
00845
00846 last()->setFunction( func );
00847 }
00848
00849
00850 }
00851
00852 void KMSearchPattern::writeConfig( KConfig * config )
const {
00853 config->writeEntry(
"name", mName);
00854 config->writeEntry(
"operator", (mOperator == KMSearchPattern::OpOr) ?
"or" :
"and" );
00855
00856
int i = 0;
00857
for (
QPtrListIterator<KMSearchRule> it( *
this ) ; it.current() && i < FILTER_MAX_RULES ; ++i , ++it )
00858
00859
00860 (*it)->writeConfig( config, i );
00861
00862
00863 config->writeEntry(
"rules", i );
00864 }
00865
00866
void KMSearchPattern::init() {
00867 clear();
00868 mOperator = OpAnd;
00869 mName =
'<' + i18n(
"name used for a virgin filter",
"unknown") +
'>';
00870 }
00871
00872 QString KMSearchPattern::asString()
const {
00873
QString result;
00874
if ( mOperator == OpOr )
00875 result = i18n(
"(match any of the following)");
00876
else
00877 result = i18n(
"(match all of the following)");
00878
00879
for (
QPtrListIterator<KMSearchRule> it( *
this ) ; it.current() ; ++it )
00880 result +=
"\n\t" + FilterLog::recode( (*it)->asString() );
00881
00882
return result;
00883 }
00884
00885 const KMSearchPattern &
KMSearchPattern::operator=(
const KMSearchPattern & other ) {
00886
if (
this == &other )
00887
return *
this;
00888
00889
setOp( other.
op() );
00890
setName( other.
name() );
00891
00892 clear();
00893
for (
QPtrListIterator<KMSearchRule> it( other ) ; it.current() ; ++it )
00894 append( KMSearchRule::createInstance( **it ) );
00895
00896
return *
this;
00897 }