You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

385 lines
11 KiB

// -*- mode: C++; c-file-style: "gnu" -*-
// kmfiltermgr.cpp
// my header
#include "kmfiltermgr.h"
#include "kmkernel.h"
// other kmail headers
#include "filterlog.h"
using KMail::FilterLog;
#include "kmfilterdlg.h"
#include "filterimporterexporter.h"
using KMail::FilterImporterExporter;
#include "messageproperty.h"
using KMail::MessageProperty;
#include <akonadi/changerecorder.h>
#include <akonadi/itemmovejob.h>
// other KDE headers
#include <kdebug.h>
#include <klocale.h>
#include <kconfig.h>
#include <kconfiggroup.h>
#include <kmime/kmime_message.h>
// other Qt headers
#include <QRegExp>
// other headers
#include <assert.h>
//-----------------------------------------------------------------------------
KMFilterMgr::KMFilterMgr( bool popFilter )
: mEditDialog( 0 ),
bPopFilter( popFilter ),
mShowLater( false ),
mDirtyBufferedFolderTarget( true ),
mBufferedFolderTarget( true )
{
if ( bPopFilter ) {
kDebug() << "pPopFilter set";
}
connect( kmkernel->monitor(), SIGNAL( collectionRemoved( const Akonadi::Collection& ) ),
this, SLOT( slotFolderRemoved( const Akonadi::Collection & ) ) );
}
//-----------------------------------------------------------------------------
KMFilterMgr::~KMFilterMgr()
{
writeConfig( false );
clear();
}
void KMFilterMgr::clear()
{
mDirtyBufferedFolderTarget = true;
qDeleteAll( mFilters );
mFilters.clear();
}
//-----------------------------------------------------------------------------
void KMFilterMgr::readConfig(void)
{
KSharedConfig::Ptr config = KMKernel::config();
clear();
if ( bPopFilter ) {
KConfigGroup group = config->group( "General" );
mShowLater = group.readEntry( "popshowDLmsgs", false );
}
mFilters = FilterImporterExporter::readFiltersFromConfig( config, bPopFilter );
}
//-----------------------------------------------------------------------------
void KMFilterMgr::writeConfig(bool withSync)
{
KSharedConfig::Ptr config = KMKernel::config();
// Now, write out the new stuff:
FilterImporterExporter::writeFiltersToConfig( mFilters, config, bPopFilter );
KConfigGroup group = config->group( "General" );
if ( bPopFilter )
group.writeEntry("popshowDLmsgs", mShowLater);
if ( withSync ) group.sync();
}
int KMFilterMgr::processPop( const Akonadi::Item & item ) const {
for ( QList<KMFilter*>::const_iterator it = mFilters.begin();
it != mFilters.end() ; ++it )
if ( (*it)->pattern()->matches( item ) )
return (*it)->action();
return NoAction;
}
bool KMFilterMgr::beginFiltering( const Akonadi::Item &item ) const
{
if (MessageProperty::filtering( item ))
return false;
MessageProperty::setFiltering( item, true );
if ( FilterLog::instance()->isLogging() ) {
FilterLog::instance()->addSeparator();
}
return true;
}
void KMFilterMgr::endFiltering( const Akonadi::Item &item ) const
{
MessageProperty::setFiltering( item, false );
}
int KMFilterMgr::process( const Akonadi::Item &item, const KMFilter * filter )
{
bool stopIt = false;
int result = 1;
if ( !filter || !item.hasPayload<KMime::Message::Ptr>() )
return 1;
if ( isMatching( item, filter ) ) {
// do the actual filtering stuff
if ( !beginFiltering( item ) ) {
return 1;
}
if ( filter->execActions( item, stopIt ) == KMFilter::CriticalError ) {
return 2;
}
const Akonadi::Collection targetFolder = MessageProperty::filterFolder( item );
endFiltering( item );
if ( targetFolder.isValid() ) {
new Akonadi::ItemMoveJob( item, targetFolder, this ); // TODO: check result
result = 0;
}
} else {
result = 1;
}
return result;
}
int KMFilterMgr::process( const Akonadi::Item &item, FilterSet set,
bool account, const QString& accountId ) {
if ( bPopFilter )
return processPop( item );
if ( set == NoSet ) {
kDebug() << "KMFilterMgr: process() called with not filter set selected";
return 1;
}
bool stopIt = false;
bool atLeastOneRuleMatched = false;
if ( !beginFiltering( item ) )
return 1;
for ( QList<KMFilter*>::const_iterator it = mFilters.constBegin();
!stopIt && it != mFilters.constEnd() ; ++it ) {
if ( ( ( (set&Inbound) && (*it)->applyOnInbound() ) &&
( !account ||
( account && (*it)->applyOnAccount( accountId ) ) ) ) ||
( (set&Outbound) && (*it)->applyOnOutbound() ) ||
( (set&BeforeOutbound) && (*it)->applyBeforeOutbound() ) ||
( (set&Explicit) && (*it)->applyOnExplicit() ) ) {
// filter is applicable
if ( isMatching( item, (*it) ) ) {
// filter matches
atLeastOneRuleMatched = true;
// execute actions:
if ( (*it)->execActions(item, stopIt) == KMFilter::CriticalError )
return 2;
}
}
}
Akonadi::Collection targetFolder = MessageProperty::filterFolder( item );
/* 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( item );
else
MessageProperty::setFiltering( item, false );
if ( targetFolder.isValid() ) {
new Akonadi::ItemMoveJob( item, targetFolder, this ); // TODO: check result
return 0;
}
return 1;
}
bool KMFilterMgr::isMatching( const Akonadi::Item& item, 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( item ) ) {
if ( FilterLog::instance()->isLogging() ) {
FilterLog::instance()->add( i18n( "<b>Filter rules have matched.</b>" ),
FilterLog::patternResult );
}
result = true;
}
return result;
}
bool KMFilterMgr::atLeastOneFilterAppliesTo( const QString& accountID ) const
{
QList<KMFilter*>::const_iterator it = mFilters.constBegin();
for ( ; it != mFilters.constEnd() ; ++it ) {
if ( (*it)->applyOnAccount( accountID ) ) {
return true;
}
}
return false;
}
bool KMFilterMgr::atLeastOneIncomingFilterAppliesTo( const QString& accountID ) const
{
QList<KMFilter*>::const_iterator 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;
QList<KMFilter*>::const_iterator it = mFilters.constBegin();
for ( ; it != mFilters.constEnd() ; ++it ) {
KMFilter *filter = *it;
QList<KMFilterAction*>::const_iterator jt = filter->actions()->constBegin();
const QList<KMFilterAction*>::const_iterator jtend = filter->actions()->constEnd();
for ( ; jt != jtend ; ++jt ) {
KMFilterActionWithFolder *f = dynamic_cast<KMFilterActionWithFolder*>(*jt);
if (!f)
continue;
QString name = f->argsAsString();
#if 0 //TODO port to akonadi
KMFolder *folder = kmkernel->imapFolderMgr()->findIdString( name );
if (folder) {
mBufferedFolderTarget = true;
return true;
}
#else
kDebug() << "AKONADI PORT: Disabled code in " << Q_FUNC_INFO;
#endif
}
}
mBufferedFolderTarget = false;
return false;
}
//-----------------------------------------------------------------------------
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, bPopFilter, checkForEmptyFilterList );
mEditDialog->setObjectName( "filterdialog" );
}
mEditDialog->show();
}
//-----------------------------------------------------------------------------
void KMFilterMgr::createFilter( const QByteArray & 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 ( QList<KMFilter*>::const_iterator 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 QList<KMFilter*> &filters,
bool replaceIfNameExists )
{
mDirtyBufferedFolderTarget = true;
beginUpdate();
if ( replaceIfNameExists ) {
QList<KMFilter*>::const_iterator it1 = filters.constBegin();
for ( ; it1 != filters.constEnd() ; ++it1 ) {
for ( int i = 0; i < mFilters.count(); i++ ) {
KMFilter *filter = mFilters[i];
if ( (*it1)->name() == filter->name() ) {
mFilters.removeAll( filter );
i = 0;
}
}
}
}
mFilters += filters;
writeConfig( true );
endUpdate();
}
void KMFilterMgr::setFilters( const QList<KMFilter*> &filters )
{
beginUpdate();
clear();
mFilters = filters;
writeConfig( true );
endUpdate();
}
void KMFilterMgr::slotFolderRemoved( const Akonadi::Collection & aFolder )
{
folderRemoved( aFolder, Akonadi::Collection() );
}
//-----------------------------------------------------------------------------
bool KMFilterMgr::folderRemoved(const Akonadi::Collection & aFolder, const Akonadi::Collection & aNewFolder)
{
mDirtyBufferedFolderTarget = true;
bool rem = false;
QList<KMFilter*>::const_iterator it = mFilters.constBegin();
for ( ; it != mFilters.constEnd() ; ++it )
if ( (*it)->folderRemoved(aFolder, aNewFolder) )
rem = true;
return rem;
}
//-----------------------------------------------------------------------------
#ifndef NDEBUG
void KMFilterMgr::dump(void) const
{
QList<KMFilter*>::const_iterator it = mFilters.constBegin();
for ( ; it != mFilters.constEnd() ; ++it ) {
kDebug() << (*it)->asString();
}
}
#endif
//-----------------------------------------------------------------------------
void KMFilterMgr::endUpdate(void)
{
emit filterListUpdated();
}
#include "kmfiltermgr.moc"