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"