kmail

kmfiltermgr.cpp

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