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