Backport r950340 | aacid | 2009-04-06 23:21:18 +0200 (Mon, 06 Apr 2009) | 4 lines
[kdepim.git] / kmail / kmfilter.cpp
blob4651c3b8e0a17ccee06f052542eec7bbbb87f246
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.
21 // my header
22 #include "kmfilter.h"
24 // other kmail headers
25 #include "kmkernel.h"
26 #include "accountmanager.h"
27 using KMail::AccountManager;
28 #include "kmacctimap.h"
29 #include "kmfilteraction.h"
30 #include "kmglobal.h"
31 #include "filterlog.h"
32 using KMail::FilterLog;
34 // other KDE headers
35 #include <klocale.h>
36 #include <kmessagebox.h>
37 #include <kdebug.h>
38 #include <kconfig.h>
39 #include <kconfiggroup.h>
41 // other headers
42 #include <assert.h>
45 KMFilter::KMFilter( bool popFilter )
46 : bPopFilter(popFilter)
48 if ( bPopFilter )
49 mAction = Down;
50 else {
51 bApplyOnInbound = true;
52 bApplyOnOutbound = false;
53 bApplyOnExplicit = true;
54 bStopProcessingHere = true;
55 bConfigureShortcut = false;
56 bConfigureToolbar = false;
57 bAutoNaming = true;
58 mApplicability = All;
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;
76 if ( bPopFilter ){
77 mAction = aFilter.mAction;
78 } else {
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() );
94 if ( desc ) {
95 KMFilterAction *f = desc->create();
96 if ( f ) {
97 f->argsFromString( action->argsAsString() );
98 mActions.append( f );
103 mAccounts.clear();
104 QList<int>::ConstIterator it2;
105 for ( it2 = aFilter.mAccounts.begin() ; it2 != aFilter.mAccounts.end() ; ++it2 )
106 mAccounts.append( *it2 );
110 KMFilter::~KMFilter()
112 if ( !bPopFilter ) {
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 );
133 switch ( result ) {
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 );
148 default:
149 break;
153 if ( status == NoResult ) // No filters matched, keep copy of message
154 status = GoOn;
156 stopIt = stopProcessingHere();
158 return status;
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 ))
168 return true;
169 return false;
172 /** No descriptions */
173 // only for bPopFilter
174 void KMFilter::setAction(const KMPopFilterAction aAction)
176 mAction = aAction;
179 // only for bPopFilter
180 KMPopFilterAction KMFilter::action()
182 return mAction;
185 // only for !bPopFilter
186 bool KMFilter::folderRemoved( KMFolder* aFolder, KMFolder* aNewFolder )
188 bool rem = false;
190 QListIterator<KMFilterAction*> it( mActions );
191 while ( it.hasNext() )
192 if ( it.next()->folderRemoved( aFolder, aNewFolder ) )
193 rem = true;
195 return rem;
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 )
210 return true;
211 if ( applicability() == ButImap ) {
212 KMAccount *account = kmkernel->acctMgr()->find( id );
213 bool result = account && !dynamic_cast<KMAcctImap*>(account);
214 return result;
216 if ( applicability() == Checked )
217 return mAccounts.contains( id );
219 return false;
223 //-----------------------------------------------------------------------------
224 void KMFilter::readConfig(KConfigGroup & config)
226 // MKSearchPattern::readConfig ensures
227 // that the pattern is purified.
228 mPattern.readConfig(config);
230 if (bPopFilter) {
231 // get the action description...
232 QString action = config.readEntry( "action" );
233 if ( action == "down" )
234 mAction = Down;
235 else if ( action == "later" )
236 mAction = Later;
237 else if ( action == "delete" )
238 mAction = Delete;
239 else
240 mAction = NoAction;
242 else {
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;
249 } else {
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 );
262 setShortcut( sc );
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;
272 mActions.clear();
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() ) );
286 if ( desc ) {
287 //...create an instance...
288 KMFilterAction *fa = desc->create();
289 if ( fa ) {
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 );
296 else
297 //...delete is else.
298 delete fa;
300 } else
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() ),
304 mPattern.name() ) );
307 mAccounts = config.readEntry( "accounts-set",QList<int>() );
312 void KMFilter::writeConfig(KConfigGroup & config) const
314 mPattern.writeConfig(config);
316 if (bPopFilter) {
317 switch ( mAction ) {
318 case Down:
319 config.writeEntry( "action", "down" );
320 break;
321 case Later:
322 config.writeEntry( "action", "later" );
323 break;
324 case Delete:
325 config.writeEntry( "action", "delete" );
326 break;
327 default:
328 config.writeEntry( "action", "" );
330 } else {
331 QStringList sets;
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 );
350 QString key;
351 int i;
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),
356 (*it)->name() );
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()
367 mPattern.purify();
369 if (!bPopFilter) {
370 QListIterator<KMFilterAction*> it( mActions );
371 it.toBack();
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 );
383 else
384 ++it2;
389 bool KMFilter::isEmpty() const
391 if (bPopFilter)
392 return mPattern.isEmpty();
393 else
394 return mPattern.isEmpty() && mActions.isEmpty() && mAccounts.isEmpty();
397 QString KMFilter::toolbarName() const
399 if ( mToolbarName.isEmpty() )
400 return name();
401 else
402 return mToolbarName;
405 #ifndef NDEBUG
406 const QString KMFilter::asString() const
408 QString result;
410 result += "Filter name: " + name() + '\n';
411 result += mPattern.asString() + '\n';
413 if (bPopFilter){
414 result += " action: ";
415 result += mAction;
416 result += '\n';
418 else {
419 QList<KMFilterAction*>::const_iterator it( mActions.begin() );
420 for ( ; it != mActions.end() ; ++it ) {
421 result += " action: ";
422 result += (*it)->label();
423 result += ' ';
424 result += (*it)->argsAsString();
425 result += '\n';
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";
434 result += '\n';
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() )
443 result += " None";
444 else for ( it2 = mAccounts.begin() ; it2 != mAccounts.end() ; ++it2 )
445 if ( kmkernel->acctMgr()->find( *it2 ) )
446 result += ' ' + kmkernel->acctMgr()->find( *it2 )->name();
447 result += '\n';
449 if ( bStopProcessingHere )
450 result += "If it matches, processing stops at this filter.\n";
452 return result;
454 #endif