|
|
|
/* -*- mode: C++; c-file-style: "gnu" -*-
|
|
|
|
* kmail: KDE mail client
|
|
|
|
* Copyright (c) 1996-1998 Stefan Taferner <taferner@kde.org>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include <config.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "kmfilter.h"
|
|
|
|
#include "kmkernel.h"
|
|
|
|
#include "accountmanager.h"
|
|
|
|
using KMail::AccountManager;
|
|
|
|
#include "kmacctimap.h"
|
|
|
|
#include "kmfilteraction.h"
|
|
|
|
#include "kmglobal.h"
|
|
|
|
#include "filterlog.h"
|
|
|
|
using KMail::FilterLog;
|
|
|
|
|
|
|
|
#include <klocale.h>
|
|
|
|
#include <kmessagebox.h>
|
|
|
|
#include <kdebug.h>
|
|
|
|
#include <kconfig.h>
|
|
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
|
|
|
|
|
|
|
KMFilter::KMFilter( KConfig* aConfig, bool popFilter )
|
|
|
|
: bPopFilter(popFilter)
|
|
|
|
{
|
|
|
|
if (!bPopFilter)
|
|
|
|
mActions.setAutoDelete( true );
|
|
|
|
|
|
|
|
if ( aConfig )
|
|
|
|
readConfig( aConfig );
|
|
|
|
else if ( bPopFilter )
|
|
|
|
mAction = Down;
|
|
|
|
else {
|
|
|
|
bApplyOnInbound = true;
|
|
|
|
bApplyOnOutbound = false;
|
|
|
|
bApplyOnExplicit = true;
|
|
|
|
bStopProcessingHere = true;
|
|
|
|
bConfigureShortcut = false;
|
|
|
|
bConfigureToolbar = false;
|
|
|
|
bAutoNaming = true;
|
|
|
|
mApplicability = All;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
KMFilter::KMFilter( const KMFilter & aFilter )
|
|
|
|
{
|
|
|
|
bPopFilter = aFilter.isPopFilter();
|
|
|
|
|
|
|
|
if ( !bPopFilter )
|
|
|
|
mActions.setAutoDelete( true );
|
|
|
|
|
|
|
|
mPattern = aFilter.mPattern;
|
|
|
|
|
|
|
|
if ( bPopFilter ){
|
|
|
|
mAction = aFilter.mAction;
|
|
|
|
} else {
|
|
|
|
bApplyOnInbound = aFilter.applyOnInbound();
|
|
|
|
bApplyOnOutbound = aFilter.applyOnOutbound();
|
|
|
|
bApplyOnExplicit = aFilter.applyOnExplicit();
|
|
|
|
bStopProcessingHere = aFilter.stopProcessingHere();
|
|
|
|
bConfigureShortcut = aFilter.configureShortcut();
|
|
|
|
bConfigureToolbar = aFilter.configureToolbar();
|
|
|
|
mApplicability = aFilter.applicability();
|
|
|
|
mIcon = aFilter.icon();
|
|
|
|
mShortcut = aFilter.shortcut();
|
|
|
|
|
|
|
|
TQPtrListIterator<KMFilterAction> it( aFilter.mActions );
|
|
|
|
for ( it.toFirst() ; it.current() ; ++it ) {
|
|
|
|
KMFilterActionDesc *desc = (*kmkernel->filterActionDict())[ (*it)->name() ];
|
|
|
|
if ( desc ) {
|
|
|
|
KMFilterAction *f = desc->create();
|
|
|
|
if ( f ) {
|
|
|
|
f->argsFromString( (*it)->argsAsString() );
|
|
|
|
mActions.append( f );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
mAccounts.clear();
|
|
|
|
TQValueListConstIterator<int> it2;
|
|
|
|
for ( it2 = aFilter.mAccounts.begin() ; it2 != aFilter.mAccounts.end() ; ++it2 )
|
|
|
|
mAccounts.append( *it2 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// only for !bPopFilter
|
|
|
|
KMFilter::ReturnCode KMFilter::execActions( KMMessage* msg, bool& stopIt ) const
|
|
|
|
{
|
|
|
|
ReturnCode status = NoResult;
|
|
|
|
|
|
|
|
TQPtrListIterator<KMFilterAction> it( mActions );
|
|
|
|
for ( it.toFirst() ; it.current() ; ++it ) {
|
|
|
|
|
|
|
|
if ( FilterLog::instance()->isLogging() ) {
|
|
|
|
TQString logText( i18n( "<b>Applying filter action:</b> %1" )
|
|
|
|
.arg( (*it)->displayString() ) );
|
|
|
|
FilterLog::instance()->add( logText, FilterLog::appliedAction );
|
|
|
|
}
|
|
|
|
|
|
|
|
KMFilterAction::ReturnCode result = (*it)->process( msg );
|
|
|
|
|
|
|
|
switch ( result ) {
|
|
|
|
case KMFilterAction::CriticalError:
|
|
|
|
if ( FilterLog::instance()->isLogging() ) {
|
|
|
|
TQString logText = TQString( "<font color=#FF0000>%1</font>" )
|
|
|
|
.arg( i18n( "A critical error occurred. Processing stops here." ) );
|
|
|
|
FilterLog::instance()->add( logText, FilterLog::appliedAction );
|
|
|
|
}
|
|
|
|
// in case it's a critical error: return immediately!
|
|
|
|
return CriticalError;
|
|
|
|
case KMFilterAction::ErrorButGoOn:
|
|
|
|
if ( FilterLog::instance()->isLogging() ) {
|
|
|
|
TQString logText = TQString( "<font color=#FF0000>%1</font>" )
|
|
|
|
.arg( i18n( "A problem was found while applying this action." ) );
|
|
|
|
FilterLog::instance()->add( logText, FilterLog::appliedAction );
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( status == NoResult ) // No filters matched, keep copy of message
|
|
|
|
status = GoOn;
|
|
|
|
|
|
|
|
stopIt = stopProcessingHere();
|
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KMFilter::requiresBody( KMMsgBase* msg )
|
|
|
|
{
|
|
|
|
if (pattern() && pattern()->requiresBody())
|
|
|
|
return true; // no pattern means always matches?
|
|
|
|
TQPtrListIterator<KMFilterAction> it( *actions() );
|
|
|
|
for ( it.toFirst() ; it.current() ; ++it )
|
|
|
|
if ((*it)->requiresBody( msg ))
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** No descriptions */
|
|
|
|
// only for bPopFilter
|
|
|
|
void KMFilter::setAction(const KMPopFilterAction aAction)
|
|
|
|
{
|
|
|
|
mAction = aAction;
|
|
|
|
}
|
|
|
|
|
|
|
|
// only for bPopFilter
|
|
|
|
KMPopFilterAction KMFilter::action()
|
|
|
|
{
|
|
|
|
return mAction;
|
|
|
|
}
|
|
|
|
|
|
|
|
// only for !bPopFilter
|
|
|
|
bool KMFilter::folderRemoved( KMFolder* aFolder, KMFolder* aNewFolder )
|
|
|
|
{
|
|
|
|
bool rem = false;
|
|
|
|
|
|
|
|
TQPtrListIterator<KMFilterAction> it( mActions );
|
|
|
|
for ( it.toFirst() ; it.current() ; ++it )
|
|
|
|
if ( (*it)->folderRemoved( aFolder, aNewFolder ) )
|
|
|
|
rem = true;
|
|
|
|
|
|
|
|
return rem;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KMFilter::setApplyOnAccount( uint id, bool aApply )
|
|
|
|
{
|
|
|
|
if (aApply && !mAccounts.tqcontains( id )) {
|
|
|
|
mAccounts.append( id );
|
|
|
|
} else if (!aApply && mAccounts.tqcontains( id )) {
|
|
|
|
mAccounts.remove( id );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KMFilter::applyOnAccount( uint id ) const
|
|
|
|
{
|
|
|
|
if ( applicability() == All )
|
|
|
|
return true;
|
|
|
|
if ( applicability() == ButImap ) {
|
|
|
|
KMAccount *account = kmkernel->acctMgr()->tqfind( id );
|
|
|
|
bool result = account && !dynamic_cast<KMAcctImap*>(account);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
if ( applicability() == Checked )
|
|
|
|
return mAccounts.tqcontains( id );
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void KMFilter::readConfig(KConfig* config)
|
|
|
|
{
|
|
|
|
// MKSearchPattern::readConfig ensures
|
|
|
|
// that the pattern is purified.
|
|
|
|
mPattern.readConfig(config);
|
|
|
|
|
|
|
|
if (bPopFilter) {
|
|
|
|
// get the action description...
|
|
|
|
TQString action = config->readEntry( "action" );
|
|
|
|
if ( action == "down" )
|
|
|
|
mAction = Down;
|
|
|
|
else if ( action == "later" )
|
|
|
|
mAction = Later;
|
|
|
|
else if ( action == "delete" )
|
|
|
|
mAction = Delete;
|
|
|
|
else
|
|
|
|
mAction = NoAction;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
TQStringList sets = config->readListEntry("apply-on");
|
|
|
|
if ( sets.isEmpty() && !config->hasKey("apply-on") ) {
|
|
|
|
bApplyOnOutbound = false;
|
|
|
|
bApplyOnInbound = true;
|
|
|
|
bApplyOnExplicit = true;
|
|
|
|
mApplicability = ButImap;
|
|
|
|
} else {
|
|
|
|
bApplyOnInbound = bool(sets.tqcontains("check-mail"));
|
|
|
|
bApplyOnOutbound = bool(sets.tqcontains("send-mail"));
|
|
|
|
bApplyOnExplicit = bool(sets.tqcontains("manual-filtering"));
|
|
|
|
mApplicability = (AccountType)config->readNumEntry( "Applicability", ButImap );
|
|
|
|
}
|
|
|
|
|
|
|
|
bStopProcessingHere = config->readBoolEntry("StopProcessingHere", true);
|
|
|
|
bConfigureShortcut = config->readBoolEntry("ConfigureShortcut", false);
|
|
|
|
TQString shortcut( config->readEntry( "Shortcut" ) );
|
|
|
|
if ( !shortcut.isEmpty() ) {
|
|
|
|
KShortcut sc( shortcut );
|
|
|
|
setShortcut( sc );
|
|
|
|
}
|
|
|
|
bConfigureToolbar = config->readBoolEntry("ConfigureToolbar", false);
|
|
|
|
bConfigureToolbar = bConfigureToolbar && bConfigureShortcut;
|
|
|
|
mIcon = config->readEntry( "Icon", "gear" );
|
|
|
|
bAutoNaming = config->readBoolEntry("AutomaticName", false);
|
|
|
|
|
|
|
|
int i, numActions;
|
|
|
|
TQString actName, argsName;
|
|
|
|
|
|
|
|
mActions.clear();
|
|
|
|
|
|
|
|
numActions = config->readNumEntry("actions",0);
|
|
|
|
if (numActions > FILTER_MAX_ACTIONS) {
|
|
|
|
numActions = FILTER_MAX_ACTIONS ;
|
|
|
|
KMessageBox::information( 0, i18n("<qt>Too many filter actions in filter rule <b>%1</b>.</qt>").arg( mPattern.name() ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
for ( i=0 ; i < numActions ; i++ ) {
|
|
|
|
actName.sprintf("action-name-%d", i);
|
|
|
|
argsName.sprintf("action-args-%d", i);
|
|
|
|
// get the action description...
|
|
|
|
KMFilterActionDesc *desc = (*kmkernel->filterActionDict())[ config->readEntry( actName ) ];
|
|
|
|
if ( desc ) {
|
|
|
|
//...create an instance...
|
|
|
|
KMFilterAction *fa = desc->create();
|
|
|
|
if ( fa ) {
|
|
|
|
//...load it with it's parameter...
|
|
|
|
fa->argsFromString( config->readEntry( argsName ) );
|
|
|
|
//...check if it's emoty and...
|
|
|
|
if ( !fa->isEmpty() )
|
|
|
|
//...append it if it's not and...
|
|
|
|
mActions.append( fa );
|
|
|
|
else
|
|
|
|
//...delete is else.
|
|
|
|
delete fa;
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
KMessageBox::information( 0 /* app-global modal dialog box */,
|
|
|
|
i18n("<qt>Unknown filter action <b>%1</b><br>in filter rule <b>%2</b>.<br>Ignoring it.</qt>")
|
|
|
|
.arg( config->readEntry( actName ) ).arg( mPattern.name() ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
mAccounts = config->readIntListEntry( "accounts-set" );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KMFilter::writeConfig(KConfig* config) const
|
|
|
|
{
|
|
|
|
mPattern.writeConfig(config);
|
|
|
|
|
|
|
|
if (bPopFilter) {
|
|
|
|
switch ( mAction ) {
|
|
|
|
case Down:
|
|
|
|
config->writeEntry( "action", "down" );
|
|
|
|
break;
|
|
|
|
case Later:
|
|
|
|
config->writeEntry( "action", "later" );
|
|
|
|
break;
|
|
|
|
case Delete:
|
|
|
|
config->writeEntry( "action", "delete" );
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
config->writeEntry( "action", "" );
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
TQStringList sets;
|
|
|
|
if ( bApplyOnInbound )
|
|
|
|
sets.append( "check-mail" );
|
|
|
|
if ( bApplyOnOutbound )
|
|
|
|
sets.append( "send-mail" );
|
|
|
|
if ( bApplyOnExplicit )
|
|
|
|
sets.append( "manual-filtering" );
|
|
|
|
config->writeEntry( "apply-on", sets );
|
|
|
|
|
|
|
|
config->writeEntry( "StopProcessingHere", bStopProcessingHere );
|
|
|
|
config->writeEntry( "ConfigureShortcut", bConfigureShortcut );
|
|
|
|
if ( !mShortcut.isNull() )
|
|
|
|
config->writeEntry( "Shortcut", mShortcut.toString() );
|
|
|
|
config->writeEntry( "ConfigureToolbar", bConfigureToolbar );
|
|
|
|
config->writeEntry( "Icon", mIcon );
|
|
|
|
config->writeEntry( "AutomaticName", bAutoNaming );
|
|
|
|
config->writeEntry( "Applicability", mApplicability );
|
|
|
|
|
|
|
|
TQString key;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
TQPtrListIterator<KMFilterAction> it( mActions );
|
|
|
|
for ( i=0, it.toFirst() ; it.current() ; ++it, ++i ) {
|
|
|
|
config->writeEntry( key.sprintf("action-name-%d", i),
|
|
|
|
(*it)->name() );
|
|
|
|
config->writeEntry( key.sprintf("action-args-%d", i),
|
|
|
|
(*it)->argsAsString() );
|
|
|
|
}
|
|
|
|
config->writeEntry( "actions", i );
|
|
|
|
config->writeEntry( "accounts-set", mAccounts );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KMFilter::purify()
|
|
|
|
{
|
|
|
|
mPattern.purify();
|
|
|
|
|
|
|
|
if (!bPopFilter) {
|
|
|
|
TQPtrListIterator<KMFilterAction> it( mActions );
|
|
|
|
it.toLast();
|
|
|
|
while ( it.current() )
|
|
|
|
if ( (*it)->isEmpty() )
|
|
|
|
mActions.remove ( (*it) );
|
|
|
|
else
|
|
|
|
--it;
|
|
|
|
|
|
|
|
// Remove invalid accounts from mAccounts - just to be tidy
|
|
|
|
TQValueListIterator<int> it2 = mAccounts.begin();
|
|
|
|
while ( it2 != mAccounts.end() ) {
|
|
|
|
if ( !kmkernel->acctMgr()->tqfind( *it2 ) )
|
|
|
|
it2 = mAccounts.remove( it2 );
|
|
|
|
else
|
|
|
|
++it2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KMFilter::isEmpty() const
|
|
|
|
{
|
|
|
|
if (bPopFilter)
|
|
|
|
return mPattern.isEmpty();
|
|
|
|
else
|
|
|
|
return mPattern.isEmpty() && mActions.isEmpty() && mAccounts.isEmpty();
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef NDEBUG
|
|
|
|
const TQString KMFilter::asString() const
|
|
|
|
{
|
|
|
|
TQString result;
|
|
|
|
|
|
|
|
result += mPattern.asString();
|
|
|
|
|
|
|
|
if (bPopFilter){
|
|
|
|
result += " action: ";
|
|
|
|
result += mAction;
|
|
|
|
result += "\n";
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
TQPtrListIterator<KMFilterAction> it( mActions );
|
|
|
|
for ( it.toFirst() ; it.current() ; ++it ) {
|
|
|
|
result += " action: ";
|
|
|
|
result += (*it)->label();
|
|
|
|
result += " ";
|
|
|
|
result += (*it)->argsAsString();
|
|
|
|
result += "\n";
|
|
|
|
}
|
|
|
|
result += "This filter belongs to the following sets:";
|
|
|
|
if ( bApplyOnInbound )
|
|
|
|
result += " Inbound";
|
|
|
|
if ( bApplyOnOutbound )
|
|
|
|
result += " Outbound";
|
|
|
|
if ( bApplyOnExplicit )
|
|
|
|
result += " Explicit";
|
|
|
|
result += "\n";
|
|
|
|
if ( bApplyOnInbound && mApplicability == All ) {
|
|
|
|
result += "This filter applies to all accounts.\n";
|
|
|
|
} else if ( bApplyOnInbound && mApplicability == ButImap ) {
|
|
|
|
result += "This filter applies to all but online IMAP accounts.\n";
|
|
|
|
} else if ( bApplyOnInbound ) {
|
|
|
|
TQValueListConstIterator<int> it2;
|
|
|
|
result += "This filter applies to the following accounts:";
|
|
|
|
if ( mAccounts.isEmpty() )
|
|
|
|
result += " None";
|
|
|
|
else for ( it2 = mAccounts.begin() ; it2 != mAccounts.end() ; ++it2 )
|
|
|
|
if ( kmkernel->acctMgr()->tqfind( *it2 ) )
|
|
|
|
result += " " + kmkernel->acctMgr()->tqfind( *it2 )->name();
|
|
|
|
result += "\n";
|
|
|
|
}
|
|
|
|
if ( bStopProcessingHere )
|
|
|
|
result += "If it matches, processing stops at this filter.\n";
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
#endif
|