00001
00002
00003
00004
00005 #ifdef HAVE_CONFIG_H
00006 #include <config.h>
00007 #endif
00008
00009 #include "kmfiltermgr.h"
00010
00011
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
00022 #include <kdebug.h>
00023 #include <klocale.h>
00024 #include <kconfig.h>
00025
00026
00027 #include <qregexp.h>
00028 #include <qvaluevector.h>
00029
00030
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
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
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
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
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
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
00314 if ( FilterLog::instance()->isLogging() ) {
00315 FilterLog::instance()->add( i18n( "<b>Filter rules have matched.</b>" ),
00316 FilterLog::patternResult );
00317 }
00318 atLeastOneRuleMatched = true;
00319
00320 if ( (*it)->execActions(msg, stopIt) == KMFilter::CriticalError )
00321 return 2;
00322 }
00323 }
00324 }
00325
00326 KMFolder *folder = MessageProperty::filterFolder( msg );
00327
00328
00329
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
00451
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"