1 /* -*- mode: C++; c-file-style: "gnu" -*-
2 * kmail: KDE mail client
3 * Copyright (c) 1996-1998 Stefan Taferner <taferner@kde.org>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24 // other kmail headers
26 #include "accountmanager.h"
27 using KMail::AccountManager
;
28 #include "kmacctimap.h"
29 #include "kmfilteraction.h"
31 #include "filterlog.h"
32 using KMail::FilterLog
;
36 #include <kmessagebox.h>
39 #include <kconfiggroup.h>
45 KMFilter::KMFilter( bool popFilter
)
46 : bPopFilter(popFilter
)
51 bApplyOnInbound
= true;
52 bApplyOnOutbound
= false;
53 bApplyOnExplicit
= true;
54 bStopProcessingHere
= true;
55 bConfigureShortcut
= false;
56 bConfigureToolbar
= false;
63 KMFilter::KMFilter( KConfigGroup
& aConfig
, bool popFilter
)
64 : bPopFilter(popFilter
)
66 readConfig( aConfig
);
70 KMFilter::KMFilter( const KMFilter
& aFilter
)
72 bPopFilter
= aFilter
.isPopFilter();
74 mPattern
= aFilter
.mPattern
;
77 mAction
= aFilter
.mAction
;
79 bApplyOnInbound
= aFilter
.applyOnInbound();
80 bApplyOnOutbound
= aFilter
.applyOnOutbound();
81 bApplyOnExplicit
= aFilter
.applyOnExplicit();
82 bStopProcessingHere
= aFilter
.stopProcessingHere();
83 bConfigureShortcut
= aFilter
.configureShortcut();
84 bConfigureToolbar
= aFilter
.configureToolbar();
85 mToolbarName
= aFilter
.toolbarName();
86 mApplicability
= aFilter
.applicability();
87 mIcon
= aFilter
.icon();
88 mShortcut
= aFilter
.shortcut();
90 QListIterator
<KMFilterAction
*> it( aFilter
.mActions
);
91 while ( it
.hasNext() ) {
92 KMFilterAction
*action
= it
.next();
93 KMFilterActionDesc
*desc
= kmkernel
->filterActionDict()->value( action
->name() );
95 KMFilterAction
*f
= desc
->create();
97 f
->argsFromString( action
->argsAsString() );
104 QList
<int>::ConstIterator it2
;
105 for ( it2
= aFilter
.mAccounts
.begin() ; it2
!= aFilter
.mAccounts
.end() ; ++it2
)
106 mAccounts
.append( *it2
);
110 KMFilter::~KMFilter()
113 qDeleteAll( mActions
);
117 // only for !bPopFilter
118 KMFilter::ReturnCode
KMFilter::execActions( KMMessage
* msg
, bool& stopIt
) const
120 ReturnCode status
= NoResult
;
122 QList
<KMFilterAction
*>::const_iterator
it( mActions
.begin() );
123 for ( ; it
!= mActions
.end() ; ++it
) {
125 if ( FilterLog::instance()->isLogging() ) {
126 QString
logText( i18n( "<b>Applying filter action:</b> %1",
127 (*it
)->displayString() ) );
128 FilterLog::instance()->add( logText
, FilterLog::appliedAction
);
131 KMFilterAction::ReturnCode result
= (*it
)->process( msg
);
134 case KMFilterAction::CriticalError
:
135 if ( FilterLog::instance()->isLogging() ) {
136 QString logText
= QString( "<font color=#FF0000>%1</font>" )
137 .arg( i18n( "A critical error occurred. Processing stops here." ) );
138 FilterLog::instance()->add( logText
, FilterLog::appliedAction
);
140 // in case it's a critical error: return immediately!
141 return CriticalError
;
142 case KMFilterAction::ErrorButGoOn
:
143 if ( FilterLog::instance()->isLogging() ) {
144 QString logText
= QString( "<font color=#FF0000>%1</font>" )
145 .arg( i18n( "A problem was found while applying this action." ) );
146 FilterLog::instance()->add( logText
, FilterLog::appliedAction
);
153 if ( status
== NoResult
) // No filters matched, keep copy of message
156 stopIt
= stopProcessingHere();
161 bool KMFilter::requiresBody( KMMsgBase
* msg
)
163 if (pattern() && pattern()->requiresBody())
164 return true; // no pattern means always matches?
165 QListIterator
<KMFilterAction
*> it( *actions() );
166 while ( it
.hasNext() )
167 if ( it
.next()->requiresBody( msg
))
172 /** No descriptions */
173 // only for bPopFilter
174 void KMFilter::setAction(const KMPopFilterAction aAction
)
179 // only for bPopFilter
180 KMPopFilterAction
KMFilter::action()
185 // only for !bPopFilter
186 bool KMFilter::folderRemoved( KMFolder
* aFolder
, KMFolder
* aNewFolder
)
190 QListIterator
<KMFilterAction
*> it( mActions
);
191 while ( it
.hasNext() )
192 if ( it
.next()->folderRemoved( aFolder
, aNewFolder
) )
198 void KMFilter::setApplyOnAccount( uint id
, bool aApply
)
200 if (aApply
&& !mAccounts
.contains( id
)) {
201 mAccounts
.append( id
);
202 } else if (!aApply
&& mAccounts
.contains( id
)) {
203 mAccounts
.removeAll( id
);
207 bool KMFilter::applyOnAccount( uint id
) const
209 if ( applicability() == All
)
211 if ( applicability() == ButImap
) {
212 KMAccount
*account
= kmkernel
->acctMgr()->find( id
);
213 bool result
= account
&& !dynamic_cast<KMAcctImap
*>(account
);
216 if ( applicability() == Checked
)
217 return mAccounts
.contains( id
);
223 //-----------------------------------------------------------------------------
224 void KMFilter::readConfig(KConfigGroup
& config
)
226 // MKSearchPattern::readConfig ensures
227 // that the pattern is purified.
228 mPattern
.readConfig(config
);
231 // get the action description...
232 QString action
= config
.readEntry( "action" );
233 if ( action
== "down" )
235 else if ( action
== "later" )
237 else if ( action
== "delete" )
243 QStringList sets
= config
.readEntry("apply-on", QStringList() );
244 if ( sets
.isEmpty() && !config
.hasKey("apply-on") ) {
245 bApplyOnOutbound
= false;
246 bApplyOnInbound
= true;
247 bApplyOnExplicit
= true;
248 mApplicability
= ButImap
;
250 bApplyOnInbound
= bool(sets
.contains("check-mail"));
251 bApplyOnOutbound
= bool(sets
.contains("send-mail"));
252 bApplyOnExplicit
= bool(sets
.contains("manual-filtering"));
253 mApplicability
= (AccountType
) config
.readEntry(
254 "Applicability", (int)ButImap
);
257 bStopProcessingHere
= config
.readEntry( "StopProcessingHere", true );
258 bConfigureShortcut
= config
.readEntry( "ConfigureShortcut", false );
259 QString
shortcut( config
.readEntry( "Shortcut", QString() ) );
260 if ( !shortcut
.isEmpty() ) {
261 KShortcut
sc( shortcut
);
264 bConfigureToolbar
= config
.readEntry( "ConfigureToolbar", false );
265 bConfigureToolbar
= bConfigureToolbar
&& bConfigureShortcut
;
266 mToolbarName
= config
.readEntry( "ToolbarName", name() );
267 mIcon
= config
.readEntry( "Icon", "system-run" );
268 bAutoNaming
= config
.readEntry( "AutomaticName", false );
270 QString actName
, argsName
;
274 int numActions
= config
.readEntry( "actions", 0 );
275 if (numActions
> FILTER_MAX_ACTIONS
) {
276 numActions
= FILTER_MAX_ACTIONS
;
277 KMessageBox::information( 0, i18n("<qt>Too many filter actions in filter rule <b>%1</b>.</qt>", mPattern
.name() ) );
280 for ( int i
=0 ; i
< numActions
; i
++ ) {
281 actName
.sprintf("action-name-%d", i
);
282 argsName
.sprintf("action-args-%d", i
);
283 // get the action description...
284 KMFilterActionDesc
*desc
= kmkernel
->filterActionDict()->value(
285 config
.readEntry( actName
, QString() ) );
287 //...create an instance...
288 KMFilterAction
*fa
= desc
->create();
290 //...load it with it's parameter...
291 fa
->argsFromString( config
.readEntry( argsName
, QString() ) );
292 //...check if it's emoty and...
293 if ( !fa
->isEmpty() )
294 //...append it if it's not and...
295 mActions
.append( fa
);
301 KMessageBox::information( 0 /* app-global modal dialog box */,
302 i18n("<qt>Unknown filter action <b>%1</b><br />in filter rule <b>%2</b>.<br />Ignoring it.</qt>",
303 config
.readEntry( actName
, QString() ),
307 mAccounts
= config
.readEntry( "accounts-set",QList
<int>() );
312 void KMFilter::writeConfig(KConfigGroup
& config
) const
314 mPattern
.writeConfig(config
);
319 config
.writeEntry( "action", "down" );
322 config
.writeEntry( "action", "later" );
325 config
.writeEntry( "action", "delete" );
328 config
.writeEntry( "action", "" );
332 if ( bApplyOnInbound
)
333 sets
.append( "check-mail" );
334 if ( bApplyOnOutbound
)
335 sets
.append( "send-mail" );
336 if ( bApplyOnExplicit
)
337 sets
.append( "manual-filtering" );
338 config
.writeEntry( "apply-on", sets
);
340 config
.writeEntry( "StopProcessingHere", bStopProcessingHere
);
341 config
.writeEntry( "ConfigureShortcut", bConfigureShortcut
);
342 if ( !mShortcut
.isEmpty() )
343 config
.writeEntry( "Shortcut", mShortcut
.toString() );
344 config
.writeEntry( "ConfigureToolbar", bConfigureToolbar
);
345 config
.writeEntry( "ToolbarName", mToolbarName
);
346 config
.writeEntry( "Icon", mIcon
);
347 config
.writeEntry( "AutomaticName", bAutoNaming
);
348 config
.writeEntry( "Applicability", (int)mApplicability
);
353 QList
<KMFilterAction
*>::const_iterator it
;
354 for ( i
=0, it
= mActions
.begin() ; it
!= mActions
.end() ; ++it
, ++i
) {
355 config
.writeEntry( key
.sprintf("action-name-%d", i
),
357 config
.writeEntry( key
.sprintf("action-args-%d", i
),
358 (*it
)->argsAsString() );
360 config
.writeEntry( "actions", i
);
361 config
.writeEntry( "accounts-set", mAccounts
);
365 void KMFilter::purify()
370 QListIterator
<KMFilterAction
*> it( mActions
);
372 while ( it
.hasPrevious() ) {
373 KMFilterAction
*action
= it
.previous();
374 if ( action
->isEmpty() )
375 mActions
.removeAll ( action
);
378 // Remove invalid accounts from mAccounts - just to be tidy
379 QList
<int>::Iterator it2
= mAccounts
.begin();
380 while ( it2
!= mAccounts
.end() ) {
381 if ( !kmkernel
->acctMgr()->find( *it2
) )
382 it2
= mAccounts
.erase( it2
);
389 bool KMFilter::isEmpty() const
392 return mPattern
.isEmpty();
394 return mPattern
.isEmpty() && mActions
.isEmpty() && mAccounts
.isEmpty();
397 QString
KMFilter::toolbarName() const
399 if ( mToolbarName
.isEmpty() )
406 const QString
KMFilter::asString() const
410 result
+= "Filter name: " + name() + '\n';
411 result
+= mPattern
.asString() + '\n';
414 result
+= " action: ";
419 QList
<KMFilterAction
*>::const_iterator
it( mActions
.begin() );
420 for ( ; it
!= mActions
.end() ; ++it
) {
421 result
+= " action: ";
422 result
+= (*it
)->label();
424 result
+= (*it
)->argsAsString();
427 result
+= "This filter belongs to the following sets:";
428 if ( bApplyOnInbound
)
429 result
+= " Inbound";
430 if ( bApplyOnOutbound
)
431 result
+= " Outbound";
432 if ( bApplyOnExplicit
)
433 result
+= " Explicit";
435 if ( bApplyOnInbound
&& mApplicability
== All
) {
436 result
+= "This filter applies to all accounts.\n";
437 } else if ( bApplyOnInbound
&& mApplicability
== ButImap
) {
438 result
+= "This filter applies to all but online IMAP accounts.\n";
439 } else if ( bApplyOnInbound
) {
440 QList
<int>::ConstIterator it2
;
441 result
+= "This filter applies to the following accounts:";
442 if ( mAccounts
.isEmpty() )
444 else for ( it2
= mAccounts
.begin() ; it2
!= mAccounts
.end() ; ++it2
)
445 if ( kmkernel
->acctMgr()->find( *it2
) )
446 result
+= ' ' + kmkernel
->acctMgr()->find( *it2
)->name();
449 if ( bStopProcessingHere
)
450 result
+= "If it matches, processing stops at this filter.\n";