kmail

kmfiltermgr.cpp

00001 // -*- mode: C++; c-file-style: "gnu" -*-
00002 // kmfiltermgr.cpp
00003 
00004 // my header
00005 #ifdef HAVE_CONFIG_H
00006 #include <config.h>
00007 #endif
00008 
00009 #include "kmfiltermgr.h"
00010 
00011 // other kmail headers
00012 #include "filterlog.h"
00013 using KMail::FilterLog;
00014 #include "kmfilterdlg.h"
00015 #include "kmfolderindex.h"
00016 #include "messageproperty.h"
00017 using KMail::MessageProperty;
00018 #include "kmfoldermgr.h"
00019 
00020 // other KDE headers
00021 #include <kdebug.h>
00022 #include <klocale.h>
00023 #include <kconfig.h>
00024 
00025 // other Qt headers
00026 #include <qregexp.h>
00027 #include <qvaluevector.h>
00028 
00029 // other headers
00030 #include <assert.h>
00031 
00032 
00033 //-----------------------------------------------------------------------------
00034 KMFilterMgr::KMFilterMgr( bool popFilter )
00035   : mEditDialog( 0 ),
00036     bPopFilter( popFilter ),
00037     mShowLater( false ),
00038     mDirtyBufferedFolderTarget( true ),
00039     mBufferedFolderTarget( true ),
00040     mRefCount( 0 )
00041 {
00042   if (bPopFilter)
00043     kdDebug(5006) << "pPopFilter set" << endl;
00044   connect( kmkernel, SIGNAL( folderRemoved( KMFolder* ) ),
00045            this, SLOT( slotFolderRemoved( KMFolder* ) ) );
00046 }
00047 
00048 
00049 //-----------------------------------------------------------------------------
00050 KMFilterMgr::~KMFilterMgr()
00051 {
00052   deref( true );
00053   writeConfig( false );
00054   clear();
00055 }
00056 
00057 void KMFilterMgr::clear()
00058 {
00059   mDirtyBufferedFolderTarget = true;
00060   for ( QValueListIterator<KMFilter*> it = mFilters.begin() ; 
00061         it != mFilters.end() ; ++it ) {
00062     delete *it;
00063   }
00064 }
00065 
00066 //-----------------------------------------------------------------------------
00067 void KMFilterMgr::readConfig(void)
00068 {
00069   KConfig* config = KMKernel::config();
00070   int numFilters;
00071   QString grpName;
00072 
00073   clear();
00074 
00075   KConfigGroupSaver saver(config, "General");
00076 
00077   if (bPopFilter) {
00078     numFilters = config->readNumEntry("popfilters",0);
00079     mShowLater = config->readNumEntry("popshowDLmsgs",0);
00080   } else {
00081     numFilters = config->readNumEntry("filters",0);
00082   }
00083 
00084   for ( int i=0 ; i < numFilters ; ++i ) {
00085     grpName.sprintf("%s #%d", (bPopFilter ? "PopFilter" : "Filter") , i);
00086     KConfigGroupSaver saver(config, grpName);
00087     KMFilter * filter = new KMFilter(config, bPopFilter);
00088     filter->purify();
00089     if ( filter->isEmpty() ) {
00090 #ifndef NDEBUG
00091       kdDebug(5006) << "KMFilter::readConfig: filter\n" << filter->asString()
00092         << "is empty!" << endl;
00093 #endif
00094       delete filter;
00095     } else
00096       mFilters.append(filter);
00097   }
00098 }
00099 
00100 
00101 //-----------------------------------------------------------------------------
00102 void KMFilterMgr::writeConfig(bool withSync)
00103 {
00104   KConfig* config = KMKernel::config();
00105 
00106   // first, delete all groups:
00107   QStringList filterGroups =
00108     config->groupList().grep( QRegExp( bPopFilter ? "PopFilter #\\d+" : "Filter #\\d+" ) );
00109   for ( QStringList::Iterator it = filterGroups.begin() ;
00110         it != filterGroups.end() ; ++it )
00111     config->deleteGroup( *it );
00112 
00113   // Now, write out the new stuff:
00114   int i = 0;
00115   QString grpName;
00116   for ( QValueListConstIterator<KMFilter*> it = mFilters.constBegin() ; 
00117         it != mFilters.constEnd() ; ++it ) {
00118     if ( !(*it)->isEmpty() ) {
00119       if ( bPopFilter )
00120         grpName.sprintf("PopFilter #%d", i);
00121       else
00122         grpName.sprintf("Filter #%d", i);
00123       KConfigGroupSaver saver(config, grpName);
00124       (*it)->writeConfig(config);
00125       ++i;
00126     }
00127   }
00128 
00129   KConfigGroupSaver saver(config, "General");
00130   if (bPopFilter) {
00131     config->writeEntry("popfilters", i);
00132     config->writeEntry("popshowDLmsgs", mShowLater);
00133   } else
00134     config->writeEntry("filters", i);
00135 
00136   if (withSync) config->sync();
00137 }
00138 
00139 
00140 int KMFilterMgr::processPop( KMMessage * msg ) const {
00141   for ( QValueListConstIterator<KMFilter*> it = mFilters.constBegin();
00142         it != mFilters.constEnd() ; ++it )
00143     if ( (*it)->pattern()->matches( msg ) )
00144       return (*it)->action();
00145   return NoAction;
00146 }
00147 
00148 bool KMFilterMgr::beginFiltering(KMMsgBase *msgBase) const
00149 {
00150   if (MessageProperty::filtering( msgBase ))
00151     return false;
00152   MessageProperty::setFiltering( msgBase, true );
00153   MessageProperty::setFilterFolder( msgBase, 0 );
00154   if ( FilterLog::instance()->isLogging() ) {
00155     FilterLog::instance()->addSeparator();
00156   }
00157   return true;
00158 }
00159 
00160 int KMFilterMgr::moveMessage(KMMessage *msg) const
00161 {
00162   if (MessageProperty::filterFolder(msg)->moveMsg( msg ) == 0) {
00163     if ( kmkernel->folderIsTrash( MessageProperty::filterFolder( msg )))
00164       KMFilterAction::sendMDN( msg, KMime::MDN::Deleted );
00165   } else {
00166     kdDebug(5006) << "KMfilterAction - couldn't move msg" << endl;
00167     return 2;
00168   }
00169   return 0;
00170 }
00171 
00172 void KMFilterMgr::endFiltering(KMMsgBase *msgBase) const
00173 {
00174   KMFolder *parent = msgBase->parent();
00175   if ( parent ) {
00176     if ( parent == MessageProperty::filterFolder( msgBase ) ) {
00177       parent->take( parent->find( msgBase ) );
00178     }
00179     else if ( ! MessageProperty::filterFolder( msgBase ) ) {
00180       int index = parent->find( msgBase );
00181       KMMessage *msg = parent->getMsg( index );
00182       parent->take( index );
00183       parent->addMsgKeepUID( msg );
00184     }
00185   }
00186   MessageProperty::setFiltering( msgBase, false );
00187 }
00188 
00189 int KMFilterMgr::process( KMMessage * msg, const KMFilter * filter ) {
00190   if ( !msg || !filter || !beginFiltering( msg ))
00191     return 1;
00192   bool stopIt = false;
00193   int result = 1;
00194 
00195   if ( FilterLog::instance()->isLogging() ) {
00196     QString logText( i18n( "<b>Evaluating filter rules:</b> " ) );
00197     logText.append( filter->pattern()->asString() );
00198     FilterLog::instance()->add( logText, FilterLog::patternDesc );
00199   }
00200 
00201   if (filter->pattern()->matches( msg )) {
00202     if ( FilterLog::instance()->isLogging() ) {
00203       FilterLog::instance()->add( i18n( "<b>Filter rules have matched.</b>" ), 
00204                                   FilterLog::patternResult );
00205     }
00206     if (filter->execActions( msg, stopIt ) == KMFilter::CriticalError)
00207       return 2;
00208 
00209     KMFolder *folder = MessageProperty::filterFolder( msg );
00210 
00211     endFiltering( msg );
00212     if (folder) {
00213       tempOpenFolder( folder );
00214       result = folder->moveMsg( msg );
00215     }
00216   } else {
00217     endFiltering( msg );
00218     result = 1;
00219   }
00220   return result;
00221 }
00222 
00223 int KMFilterMgr::process( KMMessage * msg, FilterSet set,
00224               bool account, uint accountId ) {
00225   if ( bPopFilter )
00226     return processPop( msg );
00227 
00228   if ( set == NoSet ) {
00229     kdDebug(5006) << "KMFilterMgr: process() called with not filter set selected"
00230           << endl;
00231     return 1;
00232   }
00233 
00234   bool stopIt = false;
00235   bool atLeastOneRuleMatched = false;
00236 
00237   if (!beginFiltering( msg ))
00238     return 1;
00239   for ( QValueListConstIterator<KMFilter*> it = mFilters.constBegin();
00240         !stopIt && it != mFilters.constEnd() ; ++it ) {
00241 
00242     if ( ( ( (set&Inbound) && (*it)->applyOnInbound() ) &&
00243        ( !account || 
00244          ( account && (*it)->applyOnAccount( accountId ) ) ) ) ||
00245          ( (set&Outbound)  && (*it)->applyOnOutbound() ) ||
00246          ( (set&Explicit) && (*it)->applyOnExplicit() ) ) {
00247         // filter is applicable
00248 
00249       if ( FilterLog::instance()->isLogging() ) {
00250         QString logText( i18n( "<b>Evaluating filter rules:</b> " ) );
00251         logText.append( (*it)->pattern()->asString() );
00252         FilterLog::instance()->add( logText, FilterLog::patternDesc );
00253       }
00254       if ( (*it)->pattern()->matches( msg ) ) {
00255         // filter matches
00256         if ( FilterLog::instance()->isLogging() ) {
00257           FilterLog::instance()->add( i18n( "<b>Filter rules have matched.</b>" ), 
00258                                       FilterLog::patternResult );
00259         }
00260         atLeastOneRuleMatched = true;
00261         // execute actions:
00262         if ( (*it)->execActions(msg, stopIt) == KMFilter::CriticalError )
00263           return 2;
00264       }
00265     }
00266   }
00267 
00268   KMFolder *folder = MessageProperty::filterFolder( msg );
00269   /* endFilter does a take() and addButKeepUID() to ensure the changed 
00270    * message is on disk. This is unnessecary if nothing matched, so just 
00271    * reset state and don't update the listview at all. */
00272   if ( atLeastOneRuleMatched )
00273     endFiltering( msg );
00274   else
00275     MessageProperty::setFiltering( msg, false );
00276   if (folder) {
00277     tempOpenFolder( folder );
00278     folder->moveMsg(msg);
00279     return 0;
00280   }
00281   return 1;
00282 }
00283 
00284 
00285 bool KMFilterMgr::atLeastOneFilterAppliesTo( unsigned int accountID ) const
00286 {
00287   QValueListConstIterator<KMFilter*> it = mFilters.constBegin();
00288   for ( ; it != mFilters.constEnd() ; ++it ) {
00289     if ( (*it)->applyOnAccount( accountID ) ) {
00290       return true;
00291     }
00292   }
00293   return false;
00294 }
00295 
00296 bool KMFilterMgr::atLeastOneIncomingFilterAppliesTo( unsigned int accountID ) const
00297 {
00298   QValueListConstIterator<KMFilter*> it = mFilters.constBegin();
00299   for ( ; it != mFilters.constEnd() ; ++it ) {
00300     if ( (*it)->applyOnInbound() && (*it)->applyOnAccount( accountID ) ) {
00301       return true;
00302     }
00303   }
00304   return false;
00305 }
00306 
00307 bool KMFilterMgr::atLeastOneOnlineImapFolderTarget()
00308 {
00309   if (!mDirtyBufferedFolderTarget)
00310     return mBufferedFolderTarget;
00311   
00312   mDirtyBufferedFolderTarget = false;
00313       
00314   QValueListConstIterator<KMFilter*> it = mFilters.constBegin();
00315   for ( ; it != mFilters.constEnd() ; ++it ) {
00316     KMFilter *filter = *it;
00317     QPtrListIterator<KMFilterAction> jt( *filter->actions() );
00318     for ( jt.toFirst() ; jt.current() ; ++jt ) {
00319       KMFilterActionWithFolder *f = dynamic_cast<KMFilterActionWithFolder*>(*jt);
00320       if (!f)
00321     continue;
00322       QString name = f->argsAsString();
00323       KMFolder *folder = kmkernel->imapFolderMgr()->findIdString( name );
00324       if (folder) {
00325     mBufferedFolderTarget = true;
00326     return true;
00327       }
00328     }
00329   }
00330   mBufferedFolderTarget = false;
00331   return false;
00332 }
00333 
00334 //-----------------------------------------------------------------------------
00335 void KMFilterMgr::ref(void)
00336 {
00337   mRefCount++;
00338 }
00339 
00340 //-----------------------------------------------------------------------------
00341 void KMFilterMgr::deref(bool force)
00342 {
00343   if (!force)
00344     mRefCount--;
00345   if (mRefCount < 0)
00346     mRefCount = 0;
00347   if (mRefCount && !force)
00348     return;
00349   QValueVector< KMFolder *>::const_iterator it;
00350   for ( it = mOpenFolders.constBegin(); it != mOpenFolders.constEnd(); ++it )
00351     (*it)->close();
00352   mOpenFolders.clear();
00353 }
00354 
00355 
00356 //-----------------------------------------------------------------------------
00357 int KMFilterMgr::tempOpenFolder(KMFolder* aFolder)
00358 {
00359   assert( aFolder );
00360 
00361   int rc = aFolder->open();
00362   if (rc) return rc;
00363 
00364   mOpenFolders.append( aFolder );
00365   return 0;
00366 }
00367 
00368 
00369 //-----------------------------------------------------------------------------
00370 void KMFilterMgr::openDialog( QWidget *, bool checkForEmptyFilterList )
00371 {
00372   if( !mEditDialog )
00373   {
00374     //
00375     // We can't use the parent as long as the dialog is modeless
00376     // and there is one shared dialog for all top level windows.
00377     //
00378     mEditDialog = new KMFilterDlg( 0, "filterdialog", bPopFilter, 
00379                                    checkForEmptyFilterList );
00380   }
00381   mEditDialog->show();
00382 }
00383 
00384 
00385 //-----------------------------------------------------------------------------
00386 void KMFilterMgr::createFilter( const QCString & field, const QString & value )
00387 {
00388   openDialog( 0, false );
00389   mEditDialog->createFilter( field, value );
00390 }
00391 
00392 
00393 //-----------------------------------------------------------------------------
00394 const QString KMFilterMgr::createUniqueName( const QString & name )
00395 {
00396   QString uniqueName = name;
00397   int counter = 0;
00398   bool found = true;
00399   
00400   while ( found ) {
00401     found = false;
00402     for ( QValueListConstIterator<KMFilter*> it = mFilters.constBegin();
00403           it != mFilters.constEnd(); ++it ) {
00404       if ( !( (*it)->name().compare( uniqueName ) ) ) {
00405         found = true;
00406         ++counter;
00407         uniqueName = name;
00408         uniqueName += QString( " (" ) + QString::number( counter ) 
00409                     + QString( ")" );
00410         break;
00411       }
00412     }
00413   }
00414   return uniqueName;
00415 }
00416 
00417 
00418 //-----------------------------------------------------------------------------
00419 void KMFilterMgr::appendFilters( const QValueList<KMFilter*> &filters,
00420                                  bool replaceIfNameExists )
00421 {
00422   mDirtyBufferedFolderTarget = true;
00423   beginUpdate();
00424   if ( replaceIfNameExists ) {
00425     QValueListConstIterator<KMFilter*> it1 = filters.constBegin();
00426     for ( ; it1 != filters.constEnd() ; ++it1 ) {
00427       QValueListConstIterator<KMFilter*> it2 = mFilters.constBegin();
00428       for ( ; it2 != mFilters.constEnd() ; ++it2 ) {
00429         if ( (*it1)->name() == (*it2)->name() ) {
00430           mFilters.remove( (*it2) );
00431           it2 = mFilters.constBegin();
00432         }
00433       }
00434     }
00435   }
00436   mFilters += filters;
00437   writeConfig( true );
00438   endUpdate();
00439 }
00440 
00441 void KMFilterMgr::setFilters( const QValueList<KMFilter*> &filters )
00442 {
00443   clear();
00444   mFilters = filters;
00445 }
00446 
00447 void KMFilterMgr::slotFolderRemoved( KMFolder * aFolder )
00448 {
00449   folderRemoved( aFolder, 0 );
00450 }
00451 
00452 //-----------------------------------------------------------------------------
00453 bool KMFilterMgr::folderRemoved(KMFolder* aFolder, KMFolder* aNewFolder)
00454 {
00455   mDirtyBufferedFolderTarget = true;
00456   bool rem = false;
00457   QValueListConstIterator<KMFilter*> it = mFilters.constBegin();
00458   for ( ; it != mFilters.constEnd() ; ++it )
00459     if ( (*it)->folderRemoved(aFolder, aNewFolder) ) 
00460       rem = true;
00461 
00462   return rem;
00463 }
00464 
00465 
00466 //-----------------------------------------------------------------------------
00467 #ifndef NDEBUG
00468 void KMFilterMgr::dump(void) const
00469 {
00470   
00471   QValueListConstIterator<KMFilter*> it = mFilters.constBegin();
00472   for ( ; it != mFilters.constEnd() ; ++it ) {
00473     kdDebug(5006) << (*it)->asString() << endl;
00474   }
00475 }
00476 #endif
00477 
00478 //-----------------------------------------------------------------------------
00479 void KMFilterMgr::endUpdate(void)
00480 {
00481   emit filterListUpdated();
00482 }
00483 
00484 #include "kmfiltermgr.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys