summaryrefslogtreecommitdiffstats
path: root/kmail/kmfiltermgr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kmail/kmfiltermgr.cpp')
-rw-r--r--kmail/kmfiltermgr.cpp509
1 files changed, 509 insertions, 0 deletions
diff --git a/kmail/kmfiltermgr.cpp b/kmail/kmfiltermgr.cpp
new file mode 100644
index 00000000..c75404f8
--- /dev/null
+++ b/kmail/kmfiltermgr.cpp
@@ -0,0 +1,509 @@
+// -*- mode: C++; c-file-style: "gnu" -*-
+// kmfiltermgr.cpp
+
+// my header
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "kmfiltermgr.h"
+
+// other kmail headers
+#include "filterlog.h"
+using KMail::FilterLog;
+#include "kmfilterdlg.h"
+#include "kmfolderindex.h"
+#include "filterimporterexporter.h"
+using KMail::FilterImporterExporter;
+#include "kmfoldermgr.h"
+#include "kmmsgdict.h"
+#include "messageproperty.h"
+using KMail::MessageProperty;
+
+// other KDE headers
+#include <kdebug.h>
+#include <klocale.h>
+#include <kconfig.h>
+
+// other Qt headers
+#include <qregexp.h>
+#include <qvaluevector.h>
+
+// other headers
+#include <assert.h>
+
+
+//-----------------------------------------------------------------------------
+KMFilterMgr::KMFilterMgr( bool popFilter )
+ : mEditDialog( 0 ),
+ bPopFilter( popFilter ),
+ mShowLater( false ),
+ mDirtyBufferedFolderTarget( true ),
+ mBufferedFolderTarget( true ),
+ mRefCount( 0 )
+{
+ if (bPopFilter)
+ kdDebug(5006) << "pPopFilter set" << endl;
+ connect( kmkernel, SIGNAL( folderRemoved( KMFolder* ) ),
+ this, SLOT( slotFolderRemoved( KMFolder* ) ) );
+}
+
+
+//-----------------------------------------------------------------------------
+KMFilterMgr::~KMFilterMgr()
+{
+ deref( true );
+ writeConfig( false );
+ clear();
+}
+
+void KMFilterMgr::clear()
+{
+ mDirtyBufferedFolderTarget = true;
+ for ( QValueListIterator<KMFilter*> it = mFilters.begin() ;
+ it != mFilters.end() ; ++it ) {
+ delete *it;
+ }
+}
+
+//-----------------------------------------------------------------------------
+void KMFilterMgr::readConfig(void)
+{
+ KConfig* config = KMKernel::config();
+ clear();
+
+ if (bPopFilter) {
+ KConfigGroupSaver saver(config, "General");
+ mShowLater = config->readNumEntry("popshowDLmsgs",0);
+ }
+ mFilters = FilterImporterExporter::readFiltersFromConfig( config, bPopFilter );
+}
+
+//-----------------------------------------------------------------------------
+void KMFilterMgr::writeConfig(bool withSync)
+{
+ KConfig* config = KMKernel::config();
+
+ // Now, write out the new stuff:
+ FilterImporterExporter::writeFiltersToConfig( mFilters, config, bPopFilter );
+ KConfigGroupSaver saver(config, "General");
+ if (bPopFilter)
+ config->writeEntry("popshowDLmsgs", mShowLater);
+
+ if (withSync) config->sync();
+}
+
+int KMFilterMgr::processPop( KMMessage * msg ) const {
+ for ( QValueListConstIterator<KMFilter*> it = mFilters.constBegin();
+ it != mFilters.constEnd() ; ++it )
+ if ( (*it)->pattern()->matches( msg ) )
+ return (*it)->action();
+ return NoAction;
+}
+
+bool KMFilterMgr::beginFiltering(KMMsgBase *msgBase) const
+{
+ if (MessageProperty::filtering( msgBase ))
+ return false;
+ MessageProperty::setFiltering( msgBase, true );
+ MessageProperty::setFilterFolder( msgBase, 0 );
+ if ( FilterLog::instance()->isLogging() ) {
+ FilterLog::instance()->addSeparator();
+ }
+ return true;
+}
+
+int KMFilterMgr::moveMessage(KMMessage *msg) const
+{
+ if (MessageProperty::filterFolder(msg)->moveMsg( msg ) == 0) {
+ if ( kmkernel->folderIsTrash( MessageProperty::filterFolder( msg )))
+ KMFilterAction::sendMDN( msg, KMime::MDN::Deleted );
+ } else {
+ kdDebug(5006) << "KMfilterAction - couldn't move msg" << endl;
+ return 2;
+ }
+ return 0;
+}
+
+void KMFilterMgr::endFiltering(KMMsgBase *msgBase) const
+{
+ KMFolder *parent = msgBase->parent();
+ if ( parent ) {
+ if ( parent == MessageProperty::filterFolder( msgBase ) ) {
+ parent->take( parent->find( msgBase ) );
+ }
+ else if ( ! MessageProperty::filterFolder( msgBase ) ) {
+ int index = parent->find( msgBase );
+ KMMessage *msg = parent->getMsg( index );
+ parent->take( index );
+ parent->addMsgKeepUID( msg );
+ }
+ }
+ MessageProperty::setFiltering( msgBase, false );
+}
+
+int KMFilterMgr::process( KMMessage * msg, const KMFilter * filter ) {
+ if ( !msg || !filter || !beginFiltering( msg ))
+ return 1;
+ bool stopIt = false;
+ int result = 1;
+
+ if ( FilterLog::instance()->isLogging() ) {
+ QString logText( i18n( "<b>Evaluating filter rules:</b> " ) );
+ logText.append( filter->pattern()->asString() );
+ FilterLog::instance()->add( logText, FilterLog::patternDesc );
+ }
+
+ if (filter->pattern()->matches( msg )) {
+ if ( FilterLog::instance()->isLogging() ) {
+ FilterLog::instance()->add( i18n( "<b>Filter rules have matched.</b>" ),
+ FilterLog::patternResult );
+ }
+ if (filter->execActions( msg, stopIt ) == KMFilter::CriticalError)
+ return 2;
+
+ KMFolder *folder = MessageProperty::filterFolder( msg );
+
+ endFiltering( msg );
+ if (folder) {
+ tempOpenFolder( folder );
+ result = folder->moveMsg( msg );
+ }
+ } else {
+ endFiltering( msg );
+ result = 1;
+ }
+ return result;
+}
+
+int KMFilterMgr::process( Q_UINT32 serNum, const KMFilter *filter )
+{
+ bool stopIt = false;
+ int result = 1;
+
+ if ( !filter )
+ return 1;
+
+ if ( isMatching( serNum, filter ) ) {
+ KMFolder *folder = 0;
+ int idx = -1;
+ // get the message with the serNum
+ KMMsgDict::instance()->getLocation( serNum, &folder, &idx );
+ if ( !folder || ( idx == -1 ) || ( idx >= folder->count() ) ) {
+ return 1;
+ }
+ KMFolderOpener openFolder(folder, "filtermgr");
+ KMMsgBase *msgBase = folder->getMsgBase( idx );
+ bool unGet = !msgBase->isMessage();
+ KMMessage *msg = folder->getMsg( idx );
+ // do the actual filtering stuff
+ if ( !msg || !beginFiltering( msg ) ) {
+ if ( unGet )
+ folder->unGetMsg( idx );
+ return 1;
+ }
+ if ( filter->execActions( msg, stopIt ) == KMFilter::CriticalError ) {
+ if ( unGet )
+ folder->unGetMsg( idx );
+ return 2;
+ }
+
+ KMFolder *targetFolder = MessageProperty::filterFolder( msg );
+
+ endFiltering( msg );
+ if ( targetFolder ) {
+ tempOpenFolder( targetFolder );
+ msg->setTransferInProgress( false );
+ result = targetFolder->moveMsg( msg );
+ msg->setTransferInProgress( true );
+ }
+ if ( unGet )
+ folder->unGetMsg( idx );
+ } else {
+ result = 1;
+ }
+ return result;
+}
+
+int KMFilterMgr::process( KMMessage * msg, FilterSet set,
+ bool account, uint accountId ) {
+ if ( bPopFilter )
+ return processPop( msg );
+
+ if ( set == NoSet ) {
+ kdDebug(5006) << "KMFilterMgr: process() called with not filter set selected"
+ << endl;
+ return 1;
+ }
+
+ bool stopIt = false;
+ bool atLeastOneRuleMatched = false;
+
+ if (!beginFiltering( msg ))
+ return 1;
+ for ( QValueListConstIterator<KMFilter*> it = mFilters.constBegin();
+ !stopIt && it != mFilters.constEnd() ; ++it ) {
+
+ if ( ( ( (set&Inbound) && (*it)->applyOnInbound() ) &&
+ ( !account ||
+ ( account && (*it)->applyOnAccount( accountId ) ) ) ) ||
+ ( (set&Outbound) && (*it)->applyOnOutbound() ) ||
+ ( (set&Explicit) && (*it)->applyOnExplicit() ) ) {
+ // filter is applicable
+
+ if ( FilterLog::instance()->isLogging() ) {
+ QString logText( i18n( "<b>Evaluating filter rules:</b> " ) );
+ logText.append( (*it)->pattern()->asString() );
+ FilterLog::instance()->add( logText, FilterLog::patternDesc );
+ }
+ if ( (*it)->pattern()->matches( msg ) ) {
+ // filter matches
+ if ( FilterLog::instance()->isLogging() ) {
+ FilterLog::instance()->add( i18n( "<b>Filter rules have matched.</b>" ),
+ FilterLog::patternResult );
+ }
+ atLeastOneRuleMatched = true;
+ // execute actions:
+ if ( (*it)->execActions(msg, stopIt) == KMFilter::CriticalError )
+ return 2;
+ }
+ }
+ }
+
+ KMFolder *folder = MessageProperty::filterFolder( msg );
+ /* endFilter does a take() and addButKeepUID() to ensure the changed
+ * message is on disk. This is unnessecary if nothing matched, so just
+ * reset state and don't update the listview at all. */
+ if ( atLeastOneRuleMatched )
+ endFiltering( msg );
+ else
+ MessageProperty::setFiltering( msg, false );
+ if (folder) {
+ tempOpenFolder( folder );
+ folder->moveMsg(msg);
+ return 0;
+ }
+ return 1;
+}
+
+bool KMFilterMgr::isMatching( Q_UINT32 serNum, const KMFilter *filter )
+{
+ bool result = false;
+ if ( FilterLog::instance()->isLogging() ) {
+ QString logText( i18n( "<b>Evaluating filter rules:</b> " ) );
+ logText.append( filter->pattern()->asString() );
+ FilterLog::instance()->add( logText, FilterLog::patternDesc );
+ }
+ if ( filter->pattern()->matches( serNum ) ) {
+ if ( FilterLog::instance()->isLogging() ) {
+ FilterLog::instance()->add( i18n( "<b>Filter rules have matched.</b>" ),
+ FilterLog::patternResult );
+ }
+ result = true;
+ }
+ return result;
+}
+
+bool KMFilterMgr::atLeastOneFilterAppliesTo( unsigned int accountID ) const
+{
+ QValueListConstIterator<KMFilter*> it = mFilters.constBegin();
+ for ( ; it != mFilters.constEnd() ; ++it ) {
+ if ( (*it)->applyOnAccount( accountID ) ) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool KMFilterMgr::atLeastOneIncomingFilterAppliesTo( unsigned int accountID ) const
+{
+ QValueListConstIterator<KMFilter*> it = mFilters.constBegin();
+ for ( ; it != mFilters.constEnd() ; ++it ) {
+ if ( (*it)->applyOnInbound() && (*it)->applyOnAccount( accountID ) ) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool KMFilterMgr::atLeastOneOnlineImapFolderTarget()
+{
+ if (!mDirtyBufferedFolderTarget)
+ return mBufferedFolderTarget;
+
+ mDirtyBufferedFolderTarget = false;
+
+ QValueListConstIterator<KMFilter*> it = mFilters.constBegin();
+ for ( ; it != mFilters.constEnd() ; ++it ) {
+ KMFilter *filter = *it;
+ QPtrListIterator<KMFilterAction> jt( *filter->actions() );
+ for ( jt.toFirst() ; jt.current() ; ++jt ) {
+ KMFilterActionWithFolder *f = dynamic_cast<KMFilterActionWithFolder*>(*jt);
+ if (!f)
+ continue;
+ QString name = f->argsAsString();
+ KMFolder *folder = kmkernel->imapFolderMgr()->findIdString( name );
+ if (folder) {
+ mBufferedFolderTarget = true;
+ return true;
+ }
+ }
+ }
+ mBufferedFolderTarget = false;
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+void KMFilterMgr::ref(void)
+{
+ mRefCount++;
+}
+
+//-----------------------------------------------------------------------------
+void KMFilterMgr::deref(bool force)
+{
+ if (!force)
+ mRefCount--;
+ if (mRefCount < 0)
+ mRefCount = 0;
+ if (mRefCount && !force)
+ return;
+ QValueVector< KMFolder *>::const_iterator it;
+ for ( it = mOpenFolders.constBegin(); it != mOpenFolders.constEnd(); ++it )
+ (*it)->close("filtermgr");
+ mOpenFolders.clear();
+}
+
+
+//-----------------------------------------------------------------------------
+int KMFilterMgr::tempOpenFolder(KMFolder* aFolder)
+{
+ assert( aFolder );
+
+ int rc = aFolder->open("filermgr");
+ if (rc) return rc;
+
+ mOpenFolders.append( aFolder );
+ return 0;
+}
+
+
+//-----------------------------------------------------------------------------
+void KMFilterMgr::openDialog( QWidget *, bool checkForEmptyFilterList )
+{
+ if( !mEditDialog )
+ {
+ //
+ // We can't use the parent as long as the dialog is modeless
+ // and there is one shared dialog for all top level windows.
+ //
+ mEditDialog = new KMFilterDlg( 0, "filterdialog", bPopFilter,
+ checkForEmptyFilterList );
+ }
+ mEditDialog->show();
+}
+
+
+//-----------------------------------------------------------------------------
+void KMFilterMgr::createFilter( const QCString & field, const QString & value )
+{
+ openDialog( 0, false );
+ mEditDialog->createFilter( field, value );
+}
+
+
+//-----------------------------------------------------------------------------
+const QString KMFilterMgr::createUniqueName( const QString & name )
+{
+ QString uniqueName = name;
+ int counter = 0;
+ bool found = true;
+
+ while ( found ) {
+ found = false;
+ for ( QValueListConstIterator<KMFilter*> it = mFilters.constBegin();
+ it != mFilters.constEnd(); ++it ) {
+ if ( !( (*it)->name().compare( uniqueName ) ) ) {
+ found = true;
+ ++counter;
+ uniqueName = name;
+ uniqueName += QString( " (" ) + QString::number( counter )
+ + QString( ")" );
+ break;
+ }
+ }
+ }
+ return uniqueName;
+}
+
+
+//-----------------------------------------------------------------------------
+void KMFilterMgr::appendFilters( const QValueList<KMFilter*> &filters,
+ bool replaceIfNameExists )
+{
+ mDirtyBufferedFolderTarget = true;
+ beginUpdate();
+ if ( replaceIfNameExists ) {
+ QValueListConstIterator<KMFilter*> it1 = filters.constBegin();
+ for ( ; it1 != filters.constEnd() ; ++it1 ) {
+ QValueListConstIterator<KMFilter*> it2 = mFilters.constBegin();
+ for ( ; it2 != mFilters.constEnd() ; ++it2 ) {
+ if ( (*it1)->name() == (*it2)->name() ) {
+ mFilters.remove( (*it2) );
+ it2 = mFilters.constBegin();
+ }
+ }
+ }
+ }
+ mFilters += filters;
+ writeConfig( true );
+ endUpdate();
+}
+
+void KMFilterMgr::setFilters( const QValueList<KMFilter*> &filters )
+{
+ beginUpdate();
+ clear();
+ mFilters = filters;
+ writeConfig( true );
+ endUpdate();
+}
+
+void KMFilterMgr::slotFolderRemoved( KMFolder * aFolder )
+{
+ folderRemoved( aFolder, 0 );
+}
+
+//-----------------------------------------------------------------------------
+bool KMFilterMgr::folderRemoved(KMFolder* aFolder, KMFolder* aNewFolder)
+{
+ mDirtyBufferedFolderTarget = true;
+ bool rem = false;
+ QValueListConstIterator<KMFilter*> it = mFilters.constBegin();
+ for ( ; it != mFilters.constEnd() ; ++it )
+ if ( (*it)->folderRemoved(aFolder, aNewFolder) )
+ rem = true;
+
+ return rem;
+}
+
+
+//-----------------------------------------------------------------------------
+#ifndef NDEBUG
+void KMFilterMgr::dump(void) const
+{
+
+ QValueListConstIterator<KMFilter*> it = mFilters.constBegin();
+ for ( ; it != mFilters.constEnd() ; ++it ) {
+ kdDebug(5006) << (*it)->asString() << endl;
+ }
+}
+#endif
+
+//-----------------------------------------------------------------------------
+void KMFilterMgr::endUpdate(void)
+{
+ emit filterListUpdated();
+}
+
+#include "kmfiltermgr.moc"