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 Sat May 1 11:37:34 2004 by doxygen 1.2.15 written by Dimitri van Heesch, © 1997-2003