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