kmail Library API Documentation

kmsearchpattern.cpp

00001 // kmsearchpattern.cpp 00002 // Author: Marc Mutz <Marc@Mutz.com> 00003 // This code is under GPL! 00004 00005 #include <config.h> 00006 00007 #include "kmsearchpattern.h" 00008 #include "kmmessage.h" 00009 #include "kmmsgindex.h" 00010 #include "kmmsgdict.h" 00011 00012 #include <kglobal.h> 00013 #include <klocale.h> 00014 #include <kdebug.h> 00015 #include <kconfig.h> 00016 00017 #include <qregexp.h> 00018 00019 #include <mimelib/string.h> 00020 #include <mimelib/boyermor.h> 00021 00022 #include <assert.h> 00023 00024 static const char* funcConfigNames[] = 00025 { "contains", "contains-not", "equals", "not-equal", "regexp", 00026 "not-regexp", "greater", "less-or-equal", "less", "greater-or-equal" }; 00027 static const int numFuncConfigNames = sizeof funcConfigNames / sizeof *funcConfigNames; 00028 00029 00030 //================================================== 00031 // 00032 // class KMSearchRule (was: KMFilterRule) 00033 // 00034 //================================================== 00035 00036 KMSearchRule::KMSearchRule( const QCString & field, Function func, const QString & contents ) 00037 : mField( field ), 00038 mFunction( func ), 00039 mContents( contents ) 00040 { 00041 } 00042 00043 KMSearchRule::KMSearchRule( const KMSearchRule & other ) 00044 : mField( other.mField ), 00045 mFunction( other.mFunction ), 00046 mContents( other.mContents ) 00047 { 00048 } 00049 00050 const KMSearchRule & KMSearchRule::operator=( const KMSearchRule & other ) { 00051 if ( this == &other ) 00052 return *this; 00053 00054 mField = other.mField; 00055 mFunction = other.mFunction; 00056 mContents = other.mContents; 00057 00058 return *this; 00059 } 00060 00061 KMSearchRule * KMSearchRule::createInstance( const QCString & field, 00062 Function func, 00063 const QString & contents ) 00064 { 00065 KMSearchRule *ret; 00066 if (field == "<status>") 00067 ret = new KMSearchRuleStatus( field, func, contents ); 00068 else if ( field == "<age in days>" || field == "<size>" ) 00069 ret = new KMSearchRuleNumerical( field, func, contents ); 00070 else 00071 ret = new KMSearchRuleString( field, func, contents ); 00072 00073 return ret; 00074 } 00075 00076 KMSearchRule * KMSearchRule::createInstance( const QCString & field, 00077 const char *func, 00078 const QString & contents ) 00079 { 00080 return ( createInstance( field, configValueToFunc( func ), contents ) ); 00081 } 00082 00083 KMSearchRule * KMSearchRule::createInstance( const KMSearchRule & other ) 00084 { 00085 return ( createInstance( other.field(), other.function(), other.contents() ) ); 00086 } 00087 00088 KMSearchRule * KMSearchRule::createInstanceFromConfig( const KConfig * config, int aIdx ) 00089 { 00090 const char cIdx = char( int('A') + aIdx ); 00091 00092 static const QString & field = KGlobal::staticQString( "field" ); 00093 static const QString & func = KGlobal::staticQString( "func" ); 00094 static const QString & contents = KGlobal::staticQString( "contents" ); 00095 00096 const QCString &field2 = config->readEntry( field + cIdx ).latin1(); 00097 Function func2 = configValueToFunc( config->readEntry( func + cIdx ).latin1() ); 00098 const QString & contents2 = config->readEntry( contents + cIdx ); 00099 00100 if ( field2 == "<To or Cc>" ) // backwards compat 00101 return KMSearchRule::createInstance( "<recipients>", func2, contents2 ); 00102 else 00103 return KMSearchRule::createInstance( field2, func2, contents2 ); 00104 } 00105 00106 KMSearchRule::Function KMSearchRule::configValueToFunc( const char * str ) { 00107 if ( !str ) return FuncContains; 00108 00109 for ( int i = 0 ; i < numFuncConfigNames ; ++i ) 00110 if ( qstricmp( funcConfigNames[i], str ) == 0 ) return (Function)i; 00111 00112 return FuncContains; 00113 } 00114 00115 void KMSearchRule::writeConfig( KConfig * config, int aIdx ) const { 00116 const char cIdx = char('A' + aIdx); 00117 static const QString & field = KGlobal::staticQString( "field" ); 00118 static const QString & func = KGlobal::staticQString( "func" ); 00119 static const QString & contents = KGlobal::staticQString( "contents" ); 00120 00121 config->writeEntry( field + cIdx, QString(mField) ); 00122 config->writeEntry( func + cIdx, funcConfigNames[(int)mFunction] ); 00123 config->writeEntry( contents + cIdx, mContents ); 00124 } 00125 00126 bool KMSearchRule::matches( const DwString & aStr, KMMessage & msg, 00127 const DwBoyerMoore *, int ) const 00128 { 00129 if ( !msg.isComplete() ) { 00130 msg.fromDwString( aStr ); 00131 msg.setComplete( true ); 00132 } 00133 return matches( &msg ); 00134 } 00135 00136 #ifndef NDEBUG 00137 const QString KMSearchRule::asString() const 00138 { 00139 QString result = "\"" + mField + "\" <"; 00140 result += funcConfigNames[(int)mFunction]; 00141 result += "> \"" + mContents + "\""; 00142 00143 return result; 00144 } 00145 #endif 00146 00147 00148 00149 //================================================== 00150 // 00151 // class KMSearchRuleString 00152 // 00153 //================================================== 00154 00155 KMSearchRuleString::KMSearchRuleString( const QCString & field, 00156 Function func, const QString & contents ) 00157 : KMSearchRule(field, func, contents) 00158 { 00159 if ( field.isEmpty() || field[0] == '<' ) 00160 mBmHeaderField = 0; 00161 else //TODO handle the unrealistic case of the message starting with mField 00162 mBmHeaderField = new DwBoyerMoore(("\n" + field + ": ").data()); 00163 } 00164 00165 KMSearchRuleString::KMSearchRuleString( const KMSearchRuleString & other ) 00166 : KMSearchRule( other ), 00167 mBmHeaderField( 0 ) 00168 { 00169 if ( other.mBmHeaderField ) 00170 mBmHeaderField = new DwBoyerMoore( *other.mBmHeaderField ); 00171 } 00172 00173 const KMSearchRuleString & KMSearchRuleString::operator=( const KMSearchRuleString & other ) 00174 { 00175 if ( this == &other ) 00176 return *this; 00177 00178 setField( other.field() ); 00179 mBmHeaderField = new DwBoyerMoore( *other.mBmHeaderField ); 00180 setFunction( other.function() ); 00181 setContents( other.contents() ); 00182 delete mBmHeaderField; mBmHeaderField = 0; 00183 if ( other.mBmHeaderField ) 00184 mBmHeaderField = new DwBoyerMoore( *other.mBmHeaderField ); 00185 00186 return *this; 00187 } 00188 00189 KMSearchRuleString::~KMSearchRuleString() 00190 { 00191 delete mBmHeaderField; 00192 mBmHeaderField = 0; 00193 } 00194 00195 bool KMSearchRuleString::isEmpty() const 00196 { 00197 return field().stripWhiteSpace().isEmpty() || contents().isEmpty(); 00198 } 00199 00200 bool KMSearchRuleString::requiresBody() const 00201 { 00202 if (mBmHeaderField || (field() == "<recipients>" )) 00203 return false; 00204 return true; 00205 } 00206 00207 bool KMSearchRuleString::matches( const DwString & aStr, KMMessage & msg, 00208 const DwBoyerMoore * aHeaderField, int aHeaderLen ) const 00209 { 00210 if ( isEmpty() ) 00211 return false; 00212 00213 const DwBoyerMoore * headerField = aHeaderField ? aHeaderField : mBmHeaderField ; 00214 00215 const int headerLen = ( aHeaderLen > -1 ? aHeaderLen : field().length() ) + 2 ; // +1 for ': ' 00216 00217 if ( headerField ) { 00218 static const DwBoyerMoore lf( "\n" ); 00219 static const DwBoyerMoore lflf( "\n\n" ); 00220 static const DwBoyerMoore lfcrlf( "\n\r\n" ); 00221 00222 size_t endOfHeader = lflf.FindIn( aStr, 0 ); 00223 if ( endOfHeader == DwString::npos ) 00224 endOfHeader = lfcrlf.FindIn( aStr, 0 ); 00225 const DwString headers = ( endOfHeader == DwString::npos ) ? aStr : aStr.substr( 0, endOfHeader ); 00226 size_t start = headerField->FindIn( headers, 0, false ); 00227 if ( start == DwString::npos ) 00228 return false; 00229 start += headerLen; 00230 size_t stop = lf.FindIn( aStr, start ); 00231 char ch = '\0'; 00232 while ( stop != DwString::npos && ( ch = aStr.at( stop + 1 ) ) == ' ' || ch == '\t' ) 00233 stop = lf.FindIn( aStr, stop + 1 ); 00234 const int len = stop == DwString::npos ? aStr.length() - start : stop - start ; 00235 const QCString codedValue( aStr.data() + start, len + 1 ); 00236 const QString msgContents = KMMsgBase::decodeRFC2047String( codedValue ).stripWhiteSpace(); 00237 return matchesInternal( msgContents ); 00238 } else if ( field() == "<recipients>" ) { 00239 static const DwBoyerMoore to("\nTo: "); 00240 bool res = matches( aStr, msg, &to, 2 ); 00241 if ( !res ) { 00242 static const DwBoyerMoore cc("\nCc: "); 00243 res = matches( aStr, msg, &cc, 2 ); 00244 } 00245 if ( !res ) { 00246 static const DwBoyerMoore bcc("\nBcc: "); 00247 res = matches( aStr, msg, &bcc, 3 ); 00248 } 00249 return res; 00250 } else { 00251 return KMSearchRule::matches( aStr, msg, aHeaderField, aHeaderLen ); 00252 } 00253 } 00254 00255 bool KMSearchRuleString::matches( const KMMessage * msg ) const 00256 { 00257 assert( msg ); 00258 00259 if ( isEmpty() ) 00260 return false; 00261 00262 QString msgContents; 00263 00264 if( field() == "<message>" ) { 00265 msgContents = msg->asString(); 00266 } else if ( field() == "<body>" ) { 00267 msgContents = msg->bodyDecoded(); 00268 } else if ( field() == "<any header>" ) { 00269 msgContents = msg->headerAsString(); 00270 } else if ( field() == "<recipients>" ) { 00271 // (mmutz 2001-11-05) hack to fix "<recipients> !contains foo" to 00272 // meet user's expectations. See FAQ entry in KDE 2.2.2's KMail 00273 // handbook 00274 if ( function() == FuncEquals || function() == FuncNotEqual ) 00275 // do we need to treat this case specially? Ie.: What shall 00276 // "equality" mean for recipients. 00277 return matchesInternal( msg->headerField("To") ) 00278 || matchesInternal( msg->headerField("Cc") ) 00279 || matchesInternal( msg->headerField("Bcc") ); 00280 00281 msgContents = msg->headerField("To") + msg->headerField("Cc") 00282 + msg->headerField("Bcc"); 00283 } else { 00284 msgContents = msg->headerField( field() ); 00285 } 00286 return matchesInternal( msgContents ); 00287 } 00288 00289 // helper, does the actual comparing 00290 bool KMSearchRuleString::matchesInternal( const QString & msgContents ) const 00291 { 00292 switch ( function() ) { 00293 case KMSearchRule::FuncEquals: 00294 return ( QString::compare( msgContents.lower(), contents().lower() ) == 0 ); 00295 00296 case KMSearchRule::FuncNotEqual: 00297 return ( QString::compare( msgContents.lower(), contents().lower() ) != 0 ); 00298 00299 case KMSearchRule::FuncContains: 00300 return ( msgContents.find( contents(), 0, false ) >= 0 ); 00301 00302 case KMSearchRule::FuncContainsNot: 00303 return ( msgContents.find( contents(), 0, false ) < 0 ); 00304 00305 case KMSearchRule::FuncRegExp: 00306 { 00307 QRegExp regexp( contents(), false ); 00308 return ( regexp.search( msgContents ) >= 0 ); 00309 } 00310 00311 case KMSearchRule::FuncNotRegExp: 00312 { 00313 QRegExp regexp( contents(), false ); 00314 return ( regexp.search( msgContents ) < 0 ); 00315 } 00316 00317 case FuncIsGreater: 00318 return ( QString::compare( msgContents.lower(), contents().lower() ) > 0 ); 00319 00320 case FuncIsLessOrEqual: 00321 return ( QString::compare( msgContents.lower(), contents().lower() ) <= 0 ); 00322 00323 case FuncIsLess: 00324 return ( QString::compare( msgContents.lower(), contents().lower() ) < 0 ); 00325 00326 case FuncIsGreaterOrEqual: 00327 return ( QString::compare( msgContents.lower(), contents().lower() ) >= 0 ); 00328 } 00329 00330 return false; 00331 } 00332 00333 00334 //================================================== 00335 // 00336 // class KMSearchRuleNumerical 00337 // 00338 //================================================== 00339 00340 KMSearchRuleNumerical::KMSearchRuleNumerical( const QCString & field, 00341 Function func, const QString & contents ) 00342 : KMSearchRule(field, func, contents) 00343 { 00344 } 00345 00346 bool KMSearchRuleNumerical::isEmpty() const 00347 { 00348 bool ok = false; 00349 contents().toInt( &ok ); 00350 00351 return !ok; 00352 } 00353 00354 00355 bool KMSearchRuleNumerical::matches( const KMMessage * msg ) const 00356 { 00357 00358 QString msgContents; 00359 int numericalMsgContents = 0; 00360 int numericalValue = 0; 00361 00362 if ( field() == "<size>" ) { 00363 numericalMsgContents = int( msg->msgLength() ); 00364 numericalValue = contents().toInt(); 00365 msgContents.setNum( numericalMsgContents ); 00366 } else if ( field() == "<age in days>" ) { 00367 QDateTime msgDateTime; 00368 msgDateTime.setTime_t( msg->date() ); 00369 numericalMsgContents = msgDateTime.daysTo( QDateTime::currentDateTime() ); 00370 numericalValue = contents().toInt(); 00371 msgContents.setNum( numericalMsgContents ); 00372 } 00373 return matchesInternal( numericalValue, numericalMsgContents, msgContents ); 00374 } 00375 00376 bool KMSearchRuleNumerical::matchesInternal( unsigned long numericalValue, 00377 unsigned long numericalMsgContents, const QString & msgContents ) const 00378 { 00379 switch ( function() ) { 00380 case KMSearchRule::FuncEquals: 00381 return ( numericalValue == numericalMsgContents ); 00382 00383 case KMSearchRule::FuncNotEqual: 00384 return ( numericalValue != numericalMsgContents ); 00385 00386 case KMSearchRule::FuncContains: 00387 return ( msgContents.find( contents(), 0, false ) >= 0 ); 00388 00389 case KMSearchRule::FuncContainsNot: 00390 return ( msgContents.find( contents(), 0, false ) < 0 ); 00391 00392 case KMSearchRule::FuncRegExp: 00393 { 00394 QRegExp regexp( contents(), false ); 00395 return ( regexp.search( msgContents ) >= 0 ); 00396 } 00397 00398 case KMSearchRule::FuncNotRegExp: 00399 { 00400 QRegExp regexp( contents(), false ); 00401 return ( regexp.search( msgContents ) < 0 ); 00402 } 00403 00404 case FuncIsGreater: 00405 return ( numericalMsgContents > numericalValue ); 00406 00407 case FuncIsLessOrEqual: 00408 return ( numericalMsgContents <= numericalValue ); 00409 00410 case FuncIsLess: 00411 return ( numericalMsgContents < numericalValue ); 00412 00413 case FuncIsGreaterOrEqual: 00414 return ( numericalMsgContents >= numericalValue ); 00415 } 00416 00417 return false; 00418 } 00419 00420 00421 00422 //================================================== 00423 // 00424 // class KMSearchRuleStatus 00425 // 00426 //================================================== 00427 00428 KMSearchRuleStatus::KMSearchRuleStatus( const QCString & field, 00429 Function func, const QString & aContents ) 00430 : KMSearchRule(field, func, aContents) 00431 { 00432 // the values are always in english, both from the conf file as well as 00433 // the patternedit gui 00434 if ( ! aContents.compare("new") ) 00435 mStatus = KMMsgStatusNew; 00436 if ( ! aContents.compare("unread") ) 00437 mStatus = KMMsgStatusUnread; 00438 if ( ! aContents.compare("read") ) 00439 mStatus = KMMsgStatusRead; 00440 if ( ! aContents.compare("old") ) 00441 mStatus = KMMsgStatusOld; 00442 if ( ! aContents.compare("deleted") ) 00443 mStatus = KMMsgStatusDeleted; 00444 if ( ! aContents.compare("replied") ) 00445 mStatus = KMMsgStatusReplied; 00446 if ( ! aContents.compare("forwarded") ) 00447 mStatus = KMMsgStatusForwarded; 00448 if ( ! aContents.compare("queued") ) 00449 mStatus = KMMsgStatusQueued; 00450 if ( ! aContents.compare("sent") ) 00451 mStatus = KMMsgStatusSent; 00452 if ( ! aContents.compare("important") ) 00453 mStatus = KMMsgStatusFlag; 00454 if ( ! aContents.compare("watched") ) 00455 mStatus = KMMsgStatusWatched; 00456 if ( ! aContents.compare("ignored") ) 00457 mStatus = KMMsgStatusIgnored; 00458 /* 00459 if ( ! aContents.compare("todo") ) 00460 mStatus = KMMsgStatusTodo; 00461 */ 00462 if ( ! aContents.compare("spam") ) 00463 mStatus = KMMsgStatusSpam; 00464 if ( ! aContents.compare("ham") ) 00465 mStatus = KMMsgStatusHam; 00466 } 00467 00468 bool KMSearchRuleStatus::isEmpty() const 00469 { 00470 return field().stripWhiteSpace().isEmpty() || contents().isEmpty(); 00471 } 00472 00473 bool KMSearchRuleStatus::matches( const DwString &, KMMessage &, 00474 const DwBoyerMoore *, int ) const 00475 { 00476 assert( 0 ); 00477 return false; // don't warn 00478 } 00479 00480 bool KMSearchRuleStatus::matches( const KMMessage * msg ) const 00481 { 00482 00483 KMMsgStatus msgStatus = msg->status(); 00484 00485 switch ( function() ) { 00486 case FuncEquals: // fallthrough. So that "<status> 'is' 'read'" works 00487 case FuncContains: 00488 if (msgStatus & mStatus) 00489 return true; 00490 break; 00491 case FuncNotEqual: // fallthrough. So that "<status> 'is not' 'read'" works 00492 case FuncContainsNot: 00493 if (! (msgStatus & mStatus) ) 00494 return true; 00495 break; 00496 // FIXME what about the remaining funcs, how can they make sense for 00497 // stati? 00498 default: 00499 break; 00500 } 00501 00502 return false; 00503 } 00504 00505 // ---------------------------------------------------------------------------- 00506 00507 //================================================== 00508 // 00509 // class KMSearchPattern 00510 // 00511 //================================================== 00512 00513 KMSearchPattern::KMSearchPattern( const KConfig * config ) 00514 : QPtrList<KMSearchRule>() 00515 { 00516 setAutoDelete( true ); 00517 if ( config ) 00518 readConfig( config ); 00519 else 00520 init(); 00521 } 00522 00523 KMSearchPattern::~KMSearchPattern() 00524 { 00525 } 00526 00527 bool KMSearchPattern::matches( const KMMessage * msg ) const { 00528 00529 if ( isEmpty() ) 00530 return false; 00531 QPtrListIterator<KMSearchRule> it( *this ); 00532 switch ( mOperator ) { 00533 case OpAnd: // all rules must match 00534 for ( it.toFirst() ; it.current() ; ++it ) 00535 if ( !(*it)->matches( msg ) ) 00536 return false; 00537 return true; 00538 case OpOr: // at least one rule must match 00539 for ( it.toFirst() ; it.current() ; ++it ) 00540 if ( (*it)->matches( msg ) ) 00541 return true; 00542 // fall through 00543 default: 00544 return false; 00545 } 00546 } 00547 00548 bool KMSearchPattern::matches( const DwString & aStr ) const 00549 { 00550 if ( isEmpty() ) 00551 return false; 00552 KMMessage msg; 00553 QPtrListIterator<KMSearchRule> it( *this ); 00554 switch ( mOperator ) { 00555 case OpAnd: // all rules must match 00556 for ( it.toFirst() ; it.current() ; ++it ) 00557 if ( !(*it)->matches( aStr, msg ) ) 00558 return false; 00559 return true; 00560 case OpOr: // at least one rule must match 00561 for ( it.toFirst() ; it.current() ; ++it ) 00562 if ( (*it)->matches( aStr, msg ) ) 00563 return true; 00564 // fall through 00565 default: 00566 return false; 00567 } 00568 } 00569 00570 bool KMSearchPattern::matches( Q_UINT32 serNum ) const 00571 { 00572 bool res; 00573 int idx = -1; 00574 KMFolder *folder = 0; 00575 kmkernel->msgDict()->getLocation(serNum, &folder, &idx); 00576 if (!folder || (idx == -1) || (idx >= folder->count())) { 00577 return false; 00578 } 00579 00580 folder->open(); 00581 KMMsgBase *msgBase = folder->getMsgBase(idx); 00582 if (requiresBody()) { 00583 bool unGet = !msgBase->isMessage(); 00584 KMMessage *msg = folder->getMsg(idx); 00585 res = matches( msg ); 00586 if (unGet) 00587 folder->unGetMsg(idx); 00588 } else { 00589 res = matches( folder->getDwString(idx) ); 00590 } 00591 folder->close(); 00592 return res; 00593 } 00594 00595 bool KMSearchPattern::requiresBody() const { 00596 QPtrListIterator<KMSearchRule> it( *this ); 00597 for ( it.toFirst() ; it.current() ; ++it ) 00598 if ( (*it)->requiresBody() ) 00599 return true; 00600 return false; 00601 } 00602 00603 void KMSearchPattern::purify() { 00604 QPtrListIterator<KMSearchRule> it( *this ); 00605 it.toLast(); 00606 while ( it.current() ) 00607 if ( (*it)->isEmpty() ) { 00608 #ifndef NDEBUG 00609 kdDebug(5006) << "KMSearchPattern::purify(): removing " << (*it)->asString() << endl; 00610 #endif 00611 remove( *it ); 00612 } else { 00613 --it; 00614 } 00615 } 00616 00617 void KMSearchPattern::readConfig( const KConfig * config ) { 00618 init(); 00619 00620 mName = config->readEntry("name"); 00621 if ( !config->hasKey("rules") ) { 00622 kdDebug(5006) << "KMSearchPattern::readConfig: found legacy config! Converting." << endl; 00623 importLegacyConfig( config ); 00624 return; 00625 } 00626 00627 mOperator = config->readEntry("operator") == "or" ? OpOr : OpAnd; 00628 00629 const int nRules = config->readNumEntry( "rules", 0 ); 00630 00631 for ( int i = 0 ; i < nRules ; i++ ) { 00632 KMSearchRule * r = KMSearchRule::createInstanceFromConfig( config, i ); 00633 if ( r->isEmpty() ) 00634 delete r; 00635 else 00636 append( r ); 00637 } 00638 } 00639 00640 void KMSearchPattern::importLegacyConfig( const KConfig * config ) { 00641 KMSearchRule * rule = KMSearchRule::createInstance( config->readEntry("fieldA").latin1(), 00642 config->readEntry("funcA").latin1(), 00643 config->readEntry("contentsA") ); 00644 if ( rule->isEmpty() ) { 00645 // if the first rule is invalid, 00646 // we really can't do much heuristics... 00647 delete rule; 00648 return; 00649 } 00650 append( rule ); 00651 00652 const QString sOperator = config->readEntry("operator"); 00653 if ( sOperator == "ignore" ) return; 00654 00655 rule = KMSearchRule::createInstance( config->readEntry("fieldB").latin1(), 00656 config->readEntry("funcB").latin1(), 00657 config->readEntry("contentsB") ); 00658 if ( rule->isEmpty() ) { 00659 delete rule; 00660 return; 00661 } 00662 append( rule ); 00663 00664 if ( sOperator == "or" ) { 00665 mOperator = OpOr; 00666 return; 00667 } 00668 // This is the interesting case... 00669 if ( sOperator == "unless" ) { // meaning "and not", ie we need to... 00670 // ...invert the function (e.g. "equals" <-> "doesn't equal") 00671 // We simply toggle the last bit (xor with 0x1)... This assumes that 00672 // KMSearchRule::Function's come in adjacent pairs of pros and cons 00673 KMSearchRule::Function func = last()->function(); 00674 unsigned int intFunc = (unsigned int)func; 00675 func = KMSearchRule::Function( intFunc ^ 0x1 ); 00676 00677 last()->setFunction( func ); 00678 } 00679 00680 // treat any other case as "and" (our default). 00681 } 00682 00683 void KMSearchPattern::writeConfig( KConfig * config ) const { 00684 config->writeEntry("name", mName); 00685 config->writeEntry("operator", (mOperator == KMSearchPattern::OpOr) ? "or" : "and" ); 00686 00687 int i = 0; 00688 for ( QPtrListIterator<KMSearchRule> it( *this ) ; it.current() && i < FILTER_MAX_RULES ; ++i , ++it ) 00689 // we could do this ourselves, but we want the rules to be extensible, 00690 // so we give the rule it's number and let it do the rest. 00691 (*it)->writeConfig( config, i ); 00692 00693 // save the total number of rules. 00694 config->writeEntry( "rules", i ); 00695 } 00696 00697 void KMSearchPattern::init() { 00698 clear(); 00699 mOperator = OpAnd; 00700 mName = '<' + i18n("name used for a virgin filter","unknown") + '>'; 00701 } 00702 00703 #ifndef NDEBUG 00704 QString KMSearchPattern::asString() const { 00705 QString result = "Match "; 00706 result += ( mOperator == OpOr ) ? "any" : "all"; 00707 result += " of the following:\n"; 00708 00709 for ( QPtrListIterator<KMSearchRule> it( *this ) ; it.current() ; ++it ) 00710 result += (*it)->asString() + '\n'; 00711 00712 return result; 00713 } 00714 #endif 00715 00716 const KMSearchPattern & KMSearchPattern::operator=( const KMSearchPattern & other ) { 00717 if ( this == &other ) 00718 return *this; 00719 00720 setOp( other.op() ); 00721 setName( other.name() ); 00722 00723 clear(); // ### 00724 for ( QPtrListIterator<KMSearchRule> it( other ) ; it.current() ; ++it ) 00725 append( KMSearchRule::createInstance( **it ) ); // deep copy 00726 00727 return *this; 00728 }
KDE Logo
This file is part of the documentation for kmail Library Version 3.2.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Jul 28 23:58:03 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003