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     bool opened = folder->isOpened();
00241     if ( !opened )
00242       folder->open();
00243     KMMsgBase *msgBase = folder->getMsgBase( idx );
00244     bool unGet = !msgBase->isMessage();
00245     KMMessage *msg = folder->getMsg( idx );
00246     // do the actual filtering stuff
00247     if ( !msg || !beginFiltering( msg ) ) {
00248       if ( unGet )
00249         folder->unGetMsg( idx );
00250       if ( !opened )
00251         folder->close();
00252       return 1;
00253     }
00254     if ( filter->execActions( msg, stopIt ) == KMFilter::CriticalError ) {
00255       if ( unGet )
00256         folder->unGetMsg( idx );
00257       if ( !opened )
00258         folder->close();
00259       return 2;
00260     }
00261 
00262     KMFolder *targetFolder = MessageProperty::filterFolder( msg );
00263 
00264     endFiltering( msg );
00265     if ( targetFolder ) {
00266       tempOpenFolder( targetFolder );
00267       msg->setTransferInProgress( false );
00268       result = targetFolder->moveMsg( msg );
00269       msg->setTransferInProgress( true );
00270     }
00271     if ( unGet )
00272       folder->unGetMsg( idx );
00273     if ( !opened )
00274       folder->close();
00275   } else {
00276     result = 1;
00277   }
00278   return result;
00279 }
00280 
00281 int KMFilterMgr::process( KMMessage * msg, FilterSet set,
00282               bool account, uint accountId ) {
00283   if ( bPopFilter )
00284     return processPop( msg );
00285 
00286   if ( set == NoSet ) {
00287     kdDebug(5006) << "KMFilterMgr: process() called with not filter set selected"
00288           << endl;
00289     return 1;
00290   }
00291 
00292   bool stopIt = false;
00293   bool atLeastOneRuleMatched = false;
00294 
00295   if (!beginFiltering( msg ))
00296     return 1;
00297   for ( QValueListConstIterator<KMFilter*> it = mFilters.constBegin();
00298         !stopIt && it != mFilters.constEnd() ; ++it ) {
00299 
00300     if ( ( ( (set&Inbound) && (*it)->applyOnInbound() ) &&
00301        ( !account ||
00302          ( account && (*it)->applyOnAccount( accountId ) ) ) ) ||
00303          ( (set&Outbound)  && (*it)->applyOnOutbound() ) ||
00304          ( (set&Explicit) && (*it)->applyOnExplicit() ) ) {
00305         // filter is applicable
00306 
00307       if ( FilterLog::instance()->isLogging() ) {
00308         QString logText( i18n( "<b>Evaluating filter rules:</b> " ) );
00309         logText.append( (*it)->pattern()->asString() );
00310         FilterLog::instance()->add( logText, FilterLog::patternDesc );
00311       }
00312       if ( (*it)->pattern()->matches( msg ) ) {
00313         // filter matches
00314         if ( FilterLog::instance()->isLogging() ) {
00315           FilterLog::instance()->add( i18n( "<b>Filter rules have matched.</b>" ),
00316                                       FilterLog::patternResult );
00317         }
00318         atLeastOneRuleMatched = true;
00319         // execute actions:
00320         if ( (*it)->execActions(msg, stopIt) == KMFilter::CriticalError )
00321           return 2;
00322       }
00323     }
00324   }
00325 
00326   KMFolder *folder = MessageProperty::filterFolder( msg );
00327   /* endFilter does a take() and addButKeepUID() to ensure the changed
00328    * message is on disk. This is unnessecary if nothing matched, so just
00329    * reset state and don't update the listview at all. */
00330   if ( atLeastOneRuleMatched )
00331     endFiltering( msg );
00332   else
00333     MessageProperty::setFiltering( msg, false );
00334   if (folder) {
00335     tempOpenFolder( folder );
00336     folder->moveMsg(msg);
00337     return 0;
00338   }
00339   return 1;
00340 }
00341 
00342 bool KMFilterMgr::isMatching( Q_UINT32 serNum, const KMFilter *filter )
00343 {
00344   bool result = false;
00345   if ( FilterLog::instance()->isLogging() ) {
00346     QString logText( i18n( "<b>Evaluating filter rules:</b> " ) );
00347     logText.append( filter->pattern()->asString() );
00348     FilterLog::instance()->add( logText, FilterLog::patternDesc );
00349   }
00350   if ( filter->pattern()->matches( serNum ) ) {
00351     if ( FilterLog::instance()->isLogging() ) {
00352       FilterLog::instance()->add( i18n( "<b>Filter rules have matched.</b>" ),
00353                                   FilterLog::patternResult );
00354     }
00355     result = true;
00356   }
00357   return result;
00358 }
00359 
00360 bool KMFilterMgr::atLeastOneFilterAppliesTo( unsigned int accountID ) const
00361 {
00362   QValueListConstIterator<KMFilter*> it = mFilters.constBegin();
00363   for ( ; it != mFilters.constEnd() ; ++it ) {
00364     if ( (*it)->applyOnAccount( accountID ) ) {
00365       return true;
00366     }
00367   }
00368   return false;
00369 }
00370 
00371 bool KMFilterMgr::atLeastOneIncomingFilterAppliesTo( unsigned int accountID ) const
00372 {
00373   QValueListConstIterator<KMFilter*> it = mFilters.constBegin();
00374   for ( ; it != mFilters.constEnd() ; ++it ) {
00375     if ( (*it)->applyOnInbound() && (*it)->applyOnAccount( accountID ) ) {
00376       return true;
00377     }
00378   }
00379   return false;
00380 }
00381 
00382 bool KMFilterMgr::atLeastOneOnlineImapFolderTarget()
00383 {
00384   if (!mDirtyBufferedFolderTarget)
00385     return mBufferedFolderTarget;
00386 
00387   mDirtyBufferedFolderTarget = false;
00388 
00389   QValueListConstIterator<KMFilter*> it = mFilters.constBegin();
00390   for ( ; it != mFilters.constEnd() ; ++it ) {
00391     KMFilter *filter = *it;
00392     QPtrListIterator<KMFilterAction> jt( *filter->actions() );
00393     for ( jt.toFirst() ; jt.current() ; ++jt ) {
00394       KMFilterActionWithFolder *f = dynamic_cast<KMFilterActionWithFolder*>(*jt);
00395       if (!f)
00396     continue;
00397       QString name = f->argsAsString();
00398       KMFolder *folder = kmkernel->imapFolderMgr()->findIdString( name );
00399       if (folder) {
00400     mBufferedFolderTarget = true;
00401     return true;
00402       }
00403     }
00404   }
00405   mBufferedFolderTarget = false;
00406   return false;
00407 }
00408 
00409 //-----------------------------------------------------------------------------
00410 void KMFilterMgr::ref(void)
00411 {
00412   mRefCount++;
00413 }
00414 
00415 //-----------------------------------------------------------------------------
00416 void KMFilterMgr::deref(bool force)
00417 {
00418   if (!force)
00419     mRefCount--;
00420   if (mRefCount < 0)
00421     mRefCount = 0;
00422   if (mRefCount && !force)
00423     return;
00424   QValueVector< KMFolder *>::const_iterator it;
00425   for ( it = mOpenFolders.constBegin(); it != mOpenFolders.constEnd(); ++it )
00426     (*it)->close();
00427   mOpenFolders.clear();
00428 }
00429 
00430 
00431 //-----------------------------------------------------------------------------
00432 int KMFilterMgr::tempOpenFolder(KMFolder* aFolder)
00433 {
00434   assert( aFolder );
00435 
00436   int rc = aFolder->open();
00437   if (rc) return rc;
00438 
00439   mOpenFolders.append( aFolder );
00440   return 0;
00441 }
00442 
00443 
00444 //-----------------------------------------------------------------------------
00445 void KMFilterMgr::openDialog( QWidget *, bool checkForEmptyFilterList )
00446 {
00447   if( !mEditDialog )
00448   {
00449     //
00450     // We can't use the parent as long as the dialog is modeless
00451     // and there is one shared dialog for all top level windows.
00452     //
00453     mEditDialog = new KMFilterDlg( 0, "filterdialog", bPopFilter,
00454                                    checkForEmptyFilterList );
00455   }
00456   mEditDialog->show();
00457 }
00458 
00459 
00460 //-----------------------------------------------------------------------------
00461 void KMFilterMgr::createFilter( const QCString & field, const QString & value )
00462 {
00463   openDialog( 0, false );
00464   mEditDialog->createFilter( field, value );
00465 }
00466 
00467 
00468 //-----------------------------------------------------------------------------
00469 const QString KMFilterMgr::createUniqueName( const QString & name )
00470 {
00471   QString uniqueName = name;
00472   int counter = 0;
00473   bool found = true;
00474 
00475   while ( found ) {
00476     found = false;
00477     for ( QValueListConstIterator<KMFilter*> it = mFilters.constBegin();
00478           it != mFilters.constEnd(); ++it ) {
00479       if ( !( (*it)->name().compare( uniqueName ) ) ) {
00480         found = true;
00481         ++counter;
00482         uniqueName = name;
00483         uniqueName += QString( " (" ) + QString::number( counter )
00484                     + QString( ")" );
00485         break;
00486       }
00487     }
00488   }
00489   return uniqueName;
00490 }
00491 
00492 
00493 //-----------------------------------------------------------------------------
00494 void KMFilterMgr::appendFilters( const QValueList<KMFilter*> &filters,
00495                                  bool replaceIfNameExists )
00496 {
00497   mDirtyBufferedFolderTarget = true;
00498   beginUpdate();
00499   if ( replaceIfNameExists ) {
00500     QValueListConstIterator<KMFilter*> it1 = filters.constBegin();
00501     for ( ; it1 != filters.constEnd() ; ++it1 ) {
00502       QValueListConstIterator<KMFilter*> it2 = mFilters.constBegin();
00503       for ( ; it2 != mFilters.constEnd() ; ++it2 ) {
00504         if ( (*it1)->name() == (*it2)->name() ) {
00505           mFilters.remove( (*it2) );
00506           it2 = mFilters.constBegin();
00507         }
00508       }
00509     }
00510   }
00511   mFilters += filters;
00512   writeConfig( true );
00513   endUpdate();
00514 }
00515 
00516 void KMFilterMgr::setFilters( const QValueList<KMFilter*> &filters )
00517 {
00518   clear();
00519   mFilters = filters;
00520 }
00521 
00522 void KMFilterMgr::slotFolderRemoved( KMFolder * aFolder )
00523 {
00524   folderRemoved( aFolder, 0 );
00525 }
00526 
00527 //-----------------------------------------------------------------------------
00528 bool KMFilterMgr::folderRemoved(KMFolder* aFolder, KMFolder* aNewFolder)
00529 {
00530   mDirtyBufferedFolderTarget = true;
00531   bool rem = false;
00532   QValueListConstIterator<KMFilter*> it = mFilters.constBegin();
00533   for ( ; it != mFilters.constEnd() ; ++it )
00534     if ( (*it)->folderRemoved(aFolder, aNewFolder) )
00535       rem = true;
00536 
00537   return rem;
00538 }
00539 
00540 
00541 //-----------------------------------------------------------------------------
00542 #ifndef NDEBUG
00543 void KMFilterMgr::dump(void) const
00544 {
00545 
00546   QValueListConstIterator<KMFilter*> it = mFilters.constBegin();
00547   for ( ; it != mFilters.constEnd() ; ++it ) {
00548     kdDebug(5006) << (*it)->asString() << endl;
00549   }
00550 }
00551 #endif
00552 
00553 //-----------------------------------------------------------------------------
00554 void KMFilterMgr::endUpdate(void)
00555 {
00556   emit filterListUpdated();
00557 }
00558 
00559 #include "kmfiltermgr.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys