00001
00002
00003
00004
00005 #include "kmfiltermgr.h"
00006
00007
00008 #include "filterlog.h"
00009 using KMail::FilterLog;
00010 #include "kmfilterdlg.h"
00011 #include "kmfolderindex.h"
00012 #include "filterimporterexporter.h"
00013 using KMail::FilterImporterExporter;
00014 #include "kmfoldermgr.h"
00015 #include "kmmsgdict.h"
00016 #include "messageproperty.h"
00017 using KMail::MessageProperty;
00018
00019
00020 #include <kdebug.h>
00021 #include <klocale.h>
00022 #include <kconfig.h>
00023 #include <kconfiggroup.h>
00024
00025
00026 #include <QRegExp>
00027
00028
00029 #include <assert.h>
00030
00031
00032
00033 KMFilterMgr::KMFilterMgr( bool popFilter )
00034 : mEditDialog( 0 ),
00035 bPopFilter( popFilter ),
00036 mShowLater( false ),
00037 mDirtyBufferedFolderTarget( true ),
00038 mBufferedFolderTarget( true ),
00039 mRefCount( 0 )
00040 {
00041 if (bPopFilter)
00042 kDebug(5006) <<"pPopFilter set";
00043 connect( kmkernel, SIGNAL( folderRemoved( KMFolder* ) ),
00044 this, SLOT( slotFolderRemoved( KMFolder* ) ) );
00045 }
00046
00047
00048
00049 KMFilterMgr::~KMFilterMgr()
00050 {
00051 deref( true );
00052 writeConfig( false );
00053 clear();
00054 }
00055
00056 void KMFilterMgr::clear()
00057 {
00058 mDirtyBufferedFolderTarget = true;
00059 qDeleteAll( mFilters );
00060 mFilters.clear();
00061 }
00062
00063
00064 void KMFilterMgr::readConfig(void)
00065 {
00066 KConfig* config = KMKernel::config();
00067 clear();
00068
00069 if ( bPopFilter ) {
00070 KConfigGroup group = config->group( "General" );
00071 mShowLater = group.readEntry( "popshowDLmsgs", 0 );
00072 }
00073 mFilters = FilterImporterExporter::readFiltersFromConfig( config, bPopFilter );
00074 }
00075
00076
00077 void KMFilterMgr::writeConfig(bool withSync)
00078 {
00079 KConfig* config = KMKernel::config();
00080
00081
00082 FilterImporterExporter::writeFiltersToConfig( mFilters, config, bPopFilter );
00083 KConfigGroup group = config->group( "General" );
00084 if ( bPopFilter )
00085 group.writeEntry("popshowDLmsgs", mShowLater);
00086
00087 if ( withSync ) group.sync();
00088 }
00089
00090 int KMFilterMgr::processPop( KMMessage * msg ) const {
00091 for ( QList<KMFilter*>::const_iterator it = mFilters.begin();
00092 it != mFilters.end() ; ++it )
00093 if ( (*it)->pattern()->matches( msg ) )
00094 return (*it)->action();
00095 return NoAction;
00096 }
00097
00098 bool KMFilterMgr::beginFiltering(KMMsgBase *msgBase) const
00099 {
00100 if (MessageProperty::filtering( msgBase ))
00101 return false;
00102 MessageProperty::setFiltering( msgBase, true );
00103 MessageProperty::setFilterFolder( msgBase, 0 );
00104 if ( FilterLog::instance()->isLogging() ) {
00105 FilterLog::instance()->addSeparator();
00106 }
00107 return true;
00108 }
00109
00110 int KMFilterMgr::moveMessage(KMMessage *msg) const
00111 {
00112 if (MessageProperty::filterFolder(msg)->moveMsg( msg ) == 0) {
00113 if ( kmkernel->folderIsTrash( MessageProperty::filterFolder( msg )))
00114 KMFilterAction::sendMDN( msg, KMime::MDN::Deleted );
00115 } else {
00116 kDebug(5006) <<"KMfilterAction - couldn't move msg";
00117 return 2;
00118 }
00119 return 0;
00120 }
00121
00122 void KMFilterMgr::endFiltering(KMMsgBase *msgBase) const
00123 {
00124 KMFolder *parent = msgBase->parent();
00125 if ( parent ) {
00126 if ( parent == MessageProperty::filterFolder( msgBase ) ) {
00127 parent->take( parent->find( msgBase ) );
00128 }
00129 else if ( ! MessageProperty::filterFolder( msgBase ) ) {
00130 int index = parent->find( msgBase );
00131 KMMessage *msg = parent->getMsg( index );
00132 parent->take( index );
00133 parent->addMsgKeepUID( msg );
00134 }
00135 }
00136 MessageProperty::setFiltering( msgBase, false );
00137 }
00138
00139 int KMFilterMgr::process( KMMessage * msg, const KMFilter * filter ) {
00140 bool stopIt = false;
00141 int result = 1;
00142
00143 if ( !msg || !filter || !beginFiltering( msg ))
00144 return 1;
00145
00146 if ( isMatching( msg, filter ) ) {
00147 if (filter->execActions( msg, stopIt ) == KMFilter::CriticalError)
00148 return 2;
00149
00150 KMFolder *folder = MessageProperty::filterFolder( msg );
00151
00152 endFiltering( msg );
00153 if (folder) {
00154 tempOpenFolder( folder );
00155 result = folder->moveMsg( msg );
00156 }
00157 } else {
00158 endFiltering( msg );
00159 result = 1;
00160 }
00161 return result;
00162 }
00163
00164 int KMFilterMgr::process( quint32 serNum, const KMFilter * filter ) {
00165 bool stopIt = false;
00166 int result = 1;
00167
00168 if ( !filter)
00169 return 1;
00170
00171 if ( isMatching( serNum, filter ) ) {
00172 KMFolder *folder = 0;
00173 int idx = -1;
00174
00175 KMMsgDict::instance()->getLocation(serNum, &folder, &idx);
00176 if ( !folder || ( idx == -1 ) || ( idx >= folder->count() ) ) {
00177 return 1;
00178 }
00179 KMFolderOpener openFolder( folder, "filtermgr" );
00180 KMMsgBase *msgBase = folder->getMsgBase( idx );
00181 bool unGet = !msgBase->isMessage();
00182 KMMessage *msg = folder->getMsg( idx );
00183
00184 if ( !msg || !beginFiltering( msg ) ) {
00185 if ( unGet) {
00186 folder->unGetMsg( idx );
00187 folder->close( "filtermgr" );
00188 }
00189 return 1;
00190 }
00191 if ( filter->execActions( msg, stopIt ) == KMFilter::CriticalError ) {
00192 if ( unGet ) {
00193 folder->unGetMsg( idx );
00194 folder->close( "filtermgr" );
00195 }
00196 return 2;
00197 }
00198
00199 KMFolder *targetFolder = MessageProperty::filterFolder( msg );
00200
00201 endFiltering( msg );
00202 if ( targetFolder ) {
00203 tempOpenFolder( targetFolder );
00204 msg->setTransferInProgress( false );
00205 result = targetFolder->moveMsg( msg );
00206 msg->setTransferInProgress( true );
00207 }
00208 if ( unGet) {
00209 folder->unGetMsg( idx );
00210 folder->close( "filtermgr" );
00211 }
00212 } else {
00213 result = 1;
00214 }
00215 return result;
00216 }
00217
00218 int KMFilterMgr::process( KMMessage * msg, FilterSet set,
00219 bool account, uint accountId ) {
00220 if ( bPopFilter )
00221 return processPop( msg );
00222
00223 if ( set == NoSet ) {
00224 kDebug(5006) <<"KMFilterMgr: process() called with not filter set selected";
00225 return 1;
00226 }
00227
00228 bool stopIt = false;
00229 bool atLeastOneRuleMatched = false;
00230
00231 if (!beginFiltering( msg ))
00232 return 1;
00233 for ( QList<KMFilter*>::const_iterator it = mFilters.begin();
00234 !stopIt && it != mFilters.end() ; ++it ) {
00235
00236 if ( ( ( (set&Inbound) && (*it)->applyOnInbound() ) &&
00237 ( !account ||
00238 ( account && (*it)->applyOnAccount( accountId ) ) ) ) ||
00239 ( (set&Outbound) && (*it)->applyOnOutbound() ) ||
00240 ( (set&Explicit) && (*it)->applyOnExplicit() ) ) {
00241
00242
00243 if ( isMatching( msg, (*it) ) ) {
00244
00245 atLeastOneRuleMatched = true;
00246
00247 if ( (*it)->execActions(msg, stopIt) == KMFilter::CriticalError )
00248 return 2;
00249 }
00250 }
00251 }
00252
00253 KMFolder *folder = MessageProperty::filterFolder( msg );
00254
00255
00256
00257 if ( atLeastOneRuleMatched )
00258 endFiltering( msg );
00259 else
00260 MessageProperty::setFiltering( msg, false );
00261 if (folder) {
00262 tempOpenFolder( folder );
00263 folder->moveMsg(msg);
00264 return 0;
00265 }
00266 return 1;
00267 }
00268
00269 bool KMFilterMgr::isMatching( KMMessage * msg, const KMFilter * filter )
00270 {
00271 bool result = false;
00272 if ( FilterLog::instance()->isLogging() ) {
00273 QString logText( i18n( "<b>Evaluating filter rules:</b> " ) );
00274 logText.append( filter->pattern()->asString() );
00275 FilterLog::instance()->add( logText, FilterLog::patternDesc );
00276 }
00277 if ( filter->pattern()->matches( msg ) ) {
00278 if ( FilterLog::instance()->isLogging() ) {
00279 FilterLog::instance()->add( i18n( "<b>Filter rules have matched.</b>" ),
00280 FilterLog::patternResult );
00281 }
00282 result = true;
00283 }
00284 return result;
00285 }
00286
00287 bool KMFilterMgr::isMatching( quint32 serNum, const KMFilter * filter )
00288 {
00289 bool result = false;
00290 if ( FilterLog::instance()->isLogging() ) {
00291 QString 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 QList<KMFilter*>::const_iterator it = mFilters.begin();
00308 for ( ; it != mFilters.end() ; ++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 QList<KMFilter*>::const_iterator it = mFilters.begin();
00319 for ( ; it != mFilters.end() ; ++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 QList<KMFilter*>::const_iterator it = mFilters.begin();
00335 for ( ; it != mFilters.end() ; ++it ) {
00336 KMFilter *filter = *it;
00337 QList<KMFilterAction*>::const_iterator jt = filter->actions()->begin();
00338 const QList<KMFilterAction*>::const_iterator jtend = filter->actions()->end();
00339 for ( ; jt != jtend ; ++jt ) {
00340 KMFilterActionWithFolder *f = dynamic_cast<KMFilterActionWithFolder*>(*jt);
00341 if (!f)
00342 continue;
00343 QString name = f->argsAsString();
00344 KMFolder *folder = kmkernel->imapFolderMgr()->findIdString( name );
00345 if (folder) {
00346 mBufferedFolderTarget = true;
00347 return true;
00348 }
00349 }
00350 }
00351 mBufferedFolderTarget = false;
00352 return false;
00353 }
00354
00355
00356 void KMFilterMgr::ref( void )
00357 {
00358 mRefCount++;
00359 }
00360
00361
00362 void KMFilterMgr::deref( bool force )
00363 {
00364 if ( !force ) {
00365 mRefCount--;
00366 }
00367 if ( mRefCount < 0 ) {
00368 mRefCount = 0;
00369 }
00370 if ( mRefCount && !force ) {
00371 return;
00372 }
00373 QVector< KMFolder *>::const_iterator it;
00374 for ( it = mOpenFolders.begin(); it != mOpenFolders.end(); ++it ) {
00375 (*it)->close( "filtermgr" );
00376 }
00377 mOpenFolders.clear();
00378 }
00379
00380
00381
00382 int KMFilterMgr::tempOpenFolder( KMFolder *aFolder )
00383 {
00384 assert( aFolder );
00385
00386 int rc = aFolder->open( "filtermgr" );
00387 if ( rc ) {
00388 return rc;
00389 }
00390
00391 mOpenFolders.append( aFolder );
00392 return 0;
00393 }
00394
00395
00396
00397 void KMFilterMgr::openDialog( QWidget *, bool checkForEmptyFilterList )
00398 {
00399 if( !mEditDialog )
00400 {
00401
00402
00403
00404
00405 mEditDialog = new KMFilterDlg( 0, bPopFilter, checkForEmptyFilterList );
00406 mEditDialog->setObjectName( "filterdialog" );
00407 }
00408 mEditDialog->show();
00409 }
00410
00411
00412
00413 void KMFilterMgr::createFilter( const QByteArray & field, const QString & value )
00414 {
00415 openDialog( 0, false );
00416 mEditDialog->createFilter( field, value );
00417 }
00418
00419
00420
00421 const QString KMFilterMgr::createUniqueName( const QString & name )
00422 {
00423 QString uniqueName = name;
00424 int counter = 0;
00425 bool found = true;
00426
00427 while ( found ) {
00428 found = false;
00429 for ( QList<KMFilter*>::const_iterator it = mFilters.begin();
00430 it != mFilters.end(); ++it ) {
00431 if ( !( (*it)->name().compare( uniqueName ) ) ) {
00432 found = true;
00433 ++counter;
00434 uniqueName = name;
00435 uniqueName += QString( " (" ) + QString::number( counter )
00436 + QString( ")" );
00437 break;
00438 }
00439 }
00440 }
00441 return uniqueName;
00442 }
00443
00444
00445
00446 void KMFilterMgr::appendFilters( const QList<KMFilter*> &filters,
00447 bool replaceIfNameExists )
00448 {
00449 mDirtyBufferedFolderTarget = true;
00450 beginUpdate();
00451 if ( replaceIfNameExists ) {
00452 QList<KMFilter*>::const_iterator it1 = filters.begin();
00453 for ( ; it1 != filters.end() ; ++it1 ) {
00454 for ( int i = 0; i < mFilters.count(); i++ ) {
00455 KMFilter *filter = mFilters[i];
00456 if ( (*it1)->name() == filter->name() ) {
00457 mFilters.removeAll( filter );
00458 i = 0;
00459 }
00460 }
00461 }
00462 }
00463 mFilters += filters;
00464 writeConfig( true );
00465 endUpdate();
00466 }
00467
00468 void KMFilterMgr::setFilters( const QList<KMFilter*> &filters )
00469 {
00470 beginUpdate();
00471 clear();
00472 mFilters = filters;
00473 writeConfig( true );
00474 endUpdate();
00475 }
00476
00477 void KMFilterMgr::slotFolderRemoved( KMFolder * aFolder )
00478 {
00479 folderRemoved( aFolder, 0 );
00480 }
00481
00482
00483 bool KMFilterMgr::folderRemoved(KMFolder* aFolder, KMFolder* aNewFolder)
00484 {
00485 mDirtyBufferedFolderTarget = true;
00486 bool rem = false;
00487 QList<KMFilter*>::const_iterator it = mFilters.begin();
00488 for ( ; it != mFilters.end() ; ++it )
00489 if ( (*it)->folderRemoved(aFolder, aNewFolder) )
00490 rem = true;
00491
00492 return rem;
00493 }
00494
00495
00496
00497 #ifndef NDEBUG
00498 void KMFilterMgr::dump(void) const
00499 {
00500 QList<KMFilter*>::const_iterator it = mFilters.begin();
00501 for ( ; it != mFilters.end() ; ++it ) {
00502 kDebug(5006) << (*it)->asString();
00503 }
00504 }
00505 #endif
00506
00507
00508 void KMFilterMgr::endUpdate(void)
00509 {
00510 emit filterListUpdated();
00511 }
00512
00513 #include "kmfiltermgr.moc"