kmfilter.cpp
00001 /* -*- mode: C++; c-file-style: "gnu" -*- 00002 * kmail: KDE mail client 00003 * Copyright (c) 1996-1998 Stefan Taferner <taferner@kde.org> 00004 * 00005 * This program is free software; you can redistribute it and/or modify 00006 * it under the terms of the GNU General Public License as published by 00007 * the Free Software Foundation; either version 2 of the License, or 00008 * (at your option) any later version. 00009 * 00010 * This program is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 * GNU General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU General Public License 00016 * along with this program; if not, write to the Free Software 00017 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00018 * 00019 */ 00020 #ifdef HAVE_CONFIG_H 00021 #include <config.h> 00022 #endif 00023 00024 #include "kmfilter.h" 00025 #include "kmkernel.h" 00026 #include "accountmanager.h" 00027 using KMail::AccountManager; 00028 #include "kmacctimap.h" 00029 #include "kmfilteraction.h" 00030 #include "kmglobal.h" 00031 #include "filterlog.h" 00032 using KMail::FilterLog; 00033 00034 #include <tdelocale.h> 00035 #include <tdemessagebox.h> 00036 #include <kdebug.h> 00037 #include <tdeconfig.h> 00038 00039 #include <assert.h> 00040 00041 00042 KMFilter::KMFilter( TDEConfig* aConfig, bool popFilter ) 00043 : bPopFilter(popFilter) 00044 { 00045 if (!bPopFilter) 00046 mActions.setAutoDelete( true ); 00047 00048 if ( aConfig ) 00049 readConfig( aConfig ); 00050 else if ( bPopFilter ) 00051 mAction = Down; 00052 else { 00053 bApplyOnInbound = true; 00054 bApplyOnOutbound = false; 00055 bApplyOnExplicit = true; 00056 bStopProcessingHere = true; 00057 bConfigureShortcut = false; 00058 bConfigureToolbar = false; 00059 bAutoNaming = true; 00060 mApplicability = All; 00061 } 00062 } 00063 00064 00065 KMFilter::KMFilter( const KMFilter & aFilter ) 00066 { 00067 bPopFilter = aFilter.isPopFilter(); 00068 00069 if ( !bPopFilter ) 00070 mActions.setAutoDelete( true ); 00071 00072 mPattern = aFilter.mPattern; 00073 00074 if ( bPopFilter ){ 00075 mAction = aFilter.mAction; 00076 } else { 00077 bApplyOnInbound = aFilter.applyOnInbound(); 00078 bApplyOnOutbound = aFilter.applyOnOutbound(); 00079 bApplyOnExplicit = aFilter.applyOnExplicit(); 00080 bStopProcessingHere = aFilter.stopProcessingHere(); 00081 bConfigureShortcut = aFilter.configureShortcut(); 00082 bConfigureToolbar = aFilter.configureToolbar(); 00083 mApplicability = aFilter.applicability(); 00084 mIcon = aFilter.icon(); 00085 mShortcut = aFilter.shortcut(); 00086 00087 TQPtrListIterator<KMFilterAction> it( aFilter.mActions ); 00088 for ( it.toFirst() ; it.current() ; ++it ) { 00089 KMFilterActionDesc *desc = (*kmkernel->filterActionDict())[ (*it)->name() ]; 00090 if ( desc ) { 00091 KMFilterAction *f = desc->create(); 00092 if ( f ) { 00093 f->argsFromString( (*it)->argsAsString() ); 00094 mActions.append( f ); 00095 } 00096 } 00097 } 00098 00099 mAccounts.clear(); 00100 TQValueListConstIterator<int> it2; 00101 for ( it2 = aFilter.mAccounts.begin() ; it2 != aFilter.mAccounts.end() ; ++it2 ) 00102 mAccounts.append( *it2 ); 00103 } 00104 } 00105 00106 // only for !bPopFilter 00107 KMFilter::ReturnCode KMFilter::execActions( KMMessage* msg, bool& stopIt ) const 00108 { 00109 ReturnCode status = NoResult; 00110 00111 TQPtrListIterator<KMFilterAction> it( mActions ); 00112 for ( it.toFirst() ; it.current() ; ++it ) { 00113 00114 if ( FilterLog::instance()->isLogging() ) { 00115 TQString logText( i18n( "<b>Applying filter action:</b> %1" ) 00116 .arg( (*it)->displayString() ) ); 00117 FilterLog::instance()->add( logText, FilterLog::appliedAction ); 00118 } 00119 00120 KMFilterAction::ReturnCode result = (*it)->process( msg ); 00121 00122 switch ( result ) { 00123 case KMFilterAction::CriticalError: 00124 if ( FilterLog::instance()->isLogging() ) { 00125 TQString logText = TQString( "<font color=#FF0000>%1</font>" ) 00126 .arg( i18n( "A critical error occurred. Processing stops here." ) ); 00127 FilterLog::instance()->add( logText, FilterLog::appliedAction ); 00128 } 00129 // in case it's a critical error: return immediately! 00130 return CriticalError; 00131 case KMFilterAction::ErrorButGoOn: 00132 if ( FilterLog::instance()->isLogging() ) { 00133 TQString logText = TQString( "<font color=#FF0000>%1</font>" ) 00134 .arg( i18n( "A problem was found while applying this action." ) ); 00135 FilterLog::instance()->add( logText, FilterLog::appliedAction ); 00136 } 00137 default: 00138 break; 00139 } 00140 } 00141 00142 if ( status == NoResult ) // No filters matched, keep copy of message 00143 status = GoOn; 00144 00145 stopIt = stopProcessingHere(); 00146 00147 return status; 00148 } 00149 00150 bool KMFilter::requiresBody( KMMsgBase* msg ) 00151 { 00152 if (pattern() && pattern()->requiresBody()) 00153 return true; // no pattern means always matches? 00154 TQPtrListIterator<KMFilterAction> it( *actions() ); 00155 for ( it.toFirst() ; it.current() ; ++it ) 00156 if ((*it)->requiresBody( msg )) 00157 return true; 00158 return false; 00159 } 00160 00162 // only for bPopFilter 00163 void KMFilter::setAction(const KMPopFilterAction aAction) 00164 { 00165 mAction = aAction; 00166 } 00167 00168 // only for bPopFilter 00169 KMPopFilterAction KMFilter::action() 00170 { 00171 return mAction; 00172 } 00173 00174 // only for !bPopFilter 00175 bool KMFilter::folderRemoved( KMFolder* aFolder, KMFolder* aNewFolder ) 00176 { 00177 bool rem = false; 00178 00179 TQPtrListIterator<KMFilterAction> it( mActions ); 00180 for ( it.toFirst() ; it.current() ; ++it ) 00181 if ( (*it)->folderRemoved( aFolder, aNewFolder ) ) 00182 rem = true; 00183 00184 return rem; 00185 } 00186 00187 void KMFilter::setApplyOnAccount( uint id, bool aApply ) 00188 { 00189 if (aApply && !mAccounts.contains( id )) { 00190 mAccounts.append( id ); 00191 } else if (!aApply && mAccounts.contains( id )) { 00192 mAccounts.remove( id ); 00193 } 00194 } 00195 00196 bool KMFilter::applyOnAccount( uint id ) const 00197 { 00198 if ( applicability() == All ) 00199 return true; 00200 if ( applicability() == ButImap ) { 00201 KMAccount *account = kmkernel->acctMgr()->find( id ); 00202 bool result = account && !dynamic_cast<KMAcctImap*>(account); 00203 return result; 00204 } 00205 if ( applicability() == Checked ) 00206 return mAccounts.contains( id ); 00207 00208 return false; 00209 } 00210 00211 00212 //----------------------------------------------------------------------------- 00213 void KMFilter::readConfig(TDEConfig* config) 00214 { 00215 // MKSearchPattern::readConfig ensures 00216 // that the pattern is purified. 00217 mPattern.readConfig(config); 00218 00219 if (bPopFilter) { 00220 // get the action description... 00221 TQString action = config->readEntry( "action" ); 00222 if ( action == "down" ) 00223 mAction = Down; 00224 else if ( action == "later" ) 00225 mAction = Later; 00226 else if ( action == "delete" ) 00227 mAction = Delete; 00228 else 00229 mAction = NoAction; 00230 } 00231 else { 00232 TQStringList sets = config->readListEntry("apply-on"); 00233 if ( sets.isEmpty() && !config->hasKey("apply-on") ) { 00234 bApplyOnOutbound = false; 00235 bApplyOnInbound = true; 00236 bApplyOnExplicit = true; 00237 mApplicability = ButImap; 00238 } else { 00239 bApplyOnInbound = bool(sets.contains("check-mail")); 00240 bApplyOnOutbound = bool(sets.contains("send-mail")); 00241 bApplyOnExplicit = bool(sets.contains("manual-filtering")); 00242 mApplicability = (AccountType)config->readNumEntry( "Applicability", ButImap ); 00243 } 00244 00245 bStopProcessingHere = config->readBoolEntry("StopProcessingHere", true); 00246 bConfigureShortcut = config->readBoolEntry("ConfigureShortcut", false); 00247 TQString shortcut( config->readEntry( "Shortcut" ) ); 00248 if ( !shortcut.isEmpty() ) { 00249 TDEShortcut sc( shortcut ); 00250 setShortcut( sc ); 00251 } 00252 bConfigureToolbar = config->readBoolEntry("ConfigureToolbar", false); 00253 bConfigureToolbar = bConfigureToolbar && bConfigureShortcut; 00254 mIcon = config->readEntry( "Icon", "gear" ); 00255 bAutoNaming = config->readBoolEntry("AutomaticName", false); 00256 00257 int i, numActions; 00258 TQString actName, argsName; 00259 00260 mActions.clear(); 00261 00262 numActions = config->readNumEntry("actions",0); 00263 if (numActions > FILTER_MAX_ACTIONS) { 00264 numActions = FILTER_MAX_ACTIONS ; 00265 KMessageBox::information( 0, i18n("<qt>Too many filter actions in filter rule <b>%1</b>.</qt>").arg( mPattern.name() ) ); 00266 } 00267 00268 for ( i=0 ; i < numActions ; i++ ) { 00269 actName.sprintf("action-name-%d", i); 00270 argsName.sprintf("action-args-%d", i); 00271 // get the action description... 00272 KMFilterActionDesc *desc = (*kmkernel->filterActionDict())[ config->readEntry( actName ) ]; 00273 if ( desc ) { 00274 //...create an instance... 00275 KMFilterAction *fa = desc->create(); 00276 if ( fa ) { 00277 //...load it with it's parameter... 00278 fa->argsFromString( config->readEntry( argsName ) ); 00279 //...check if it's emoty and... 00280 if ( !fa->isEmpty() ) 00281 //...append it if it's not and... 00282 mActions.append( fa ); 00283 else 00284 //...delete is else. 00285 delete fa; 00286 } 00287 } else 00288 KMessageBox::information( 0 /* app-global modal dialog box */, 00289 i18n("<qt>Unknown filter action <b>%1</b><br>in filter rule <b>%2</b>.<br>Ignoring it.</qt>") 00290 .arg( config->readEntry( actName ) ).arg( mPattern.name() ) ); 00291 } 00292 00293 mAccounts = config->readIntListEntry( "accounts-set" ); 00294 } 00295 } 00296 00297 00298 void KMFilter::writeConfig(TDEConfig* config) const 00299 { 00300 mPattern.writeConfig(config); 00301 00302 if (bPopFilter) { 00303 switch ( mAction ) { 00304 case Down: 00305 config->writeEntry( "action", "down" ); 00306 break; 00307 case Later: 00308 config->writeEntry( "action", "later" ); 00309 break; 00310 case Delete: 00311 config->writeEntry( "action", "delete" ); 00312 break; 00313 default: 00314 config->writeEntry( "action", "" ); 00315 } 00316 } else { 00317 TQStringList sets; 00318 if ( bApplyOnInbound ) 00319 sets.append( "check-mail" ); 00320 if ( bApplyOnOutbound ) 00321 sets.append( "send-mail" ); 00322 if ( bApplyOnExplicit ) 00323 sets.append( "manual-filtering" ); 00324 config->writeEntry( "apply-on", sets ); 00325 00326 config->writeEntry( "StopProcessingHere", bStopProcessingHere ); 00327 config->writeEntry( "ConfigureShortcut", bConfigureShortcut ); 00328 if ( !mShortcut.isNull() ) 00329 config->writeEntry( "Shortcut", mShortcut.toString() ); 00330 config->writeEntry( "ConfigureToolbar", bConfigureToolbar ); 00331 config->writeEntry( "Icon", mIcon ); 00332 config->writeEntry( "AutomaticName", bAutoNaming ); 00333 config->writeEntry( "Applicability", mApplicability ); 00334 00335 TQString key; 00336 int i; 00337 00338 TQPtrListIterator<KMFilterAction> it( mActions ); 00339 for ( i=0, it.toFirst() ; it.current() ; ++it, ++i ) { 00340 config->writeEntry( key.sprintf("action-name-%d", i), 00341 (*it)->name() ); 00342 config->writeEntry( key.sprintf("action-args-%d", i), 00343 (*it)->argsAsString() ); 00344 } 00345 config->writeEntry( "actions", i ); 00346 config->writeEntry( "accounts-set", mAccounts ); 00347 } 00348 } 00349 00350 void KMFilter::purify() 00351 { 00352 mPattern.purify(); 00353 00354 if (!bPopFilter) { 00355 TQPtrListIterator<KMFilterAction> it( mActions ); 00356 it.toLast(); 00357 while ( it.current() ) 00358 if ( (*it)->isEmpty() ) 00359 mActions.remove ( (*it) ); 00360 else 00361 --it; 00362 00363 // Remove invalid accounts from mAccounts - just to be tidy 00364 TQValueListIterator<int> it2 = mAccounts.begin(); 00365 while ( it2 != mAccounts.end() ) { 00366 if ( !kmkernel->acctMgr()->find( *it2 ) ) 00367 it2 = mAccounts.remove( it2 ); 00368 else 00369 ++it2; 00370 } 00371 } 00372 } 00373 00374 bool KMFilter::isEmpty() const 00375 { 00376 if (bPopFilter) 00377 return mPattern.isEmpty(); 00378 else 00379 return mPattern.isEmpty() && mActions.isEmpty() && mAccounts.isEmpty(); 00380 } 00381 00382 #ifndef NDEBUG 00383 const TQString KMFilter::asString() const 00384 { 00385 TQString result; 00386 00387 result += mPattern.asString(); 00388 00389 if (bPopFilter){ 00390 result += " action: "; 00391 result += mAction; 00392 result += "\n"; 00393 } 00394 else { 00395 TQPtrListIterator<KMFilterAction> it( mActions ); 00396 for ( it.toFirst() ; it.current() ; ++it ) { 00397 result += " action: "; 00398 result += (*it)->label(); 00399 result += " "; 00400 result += (*it)->argsAsString(); 00401 result += "\n"; 00402 } 00403 result += "This filter belongs to the following sets:"; 00404 if ( bApplyOnInbound ) 00405 result += " Inbound"; 00406 if ( bApplyOnOutbound ) 00407 result += " Outbound"; 00408 if ( bApplyOnExplicit ) 00409 result += " Explicit"; 00410 result += "\n"; 00411 if ( bApplyOnInbound && mApplicability == All ) { 00412 result += "This filter applies to all accounts.\n"; 00413 } else if ( bApplyOnInbound && mApplicability == ButImap ) { 00414 result += "This filter applies to all but online IMAP accounts.\n"; 00415 } else if ( bApplyOnInbound ) { 00416 TQValueListConstIterator<int> it2; 00417 result += "This filter applies to the following accounts:"; 00418 if ( mAccounts.isEmpty() ) 00419 result += " None"; 00420 else for ( it2 = mAccounts.begin() ; it2 != mAccounts.end() ; ++it2 ) 00421 if ( kmkernel->acctMgr()->find( *it2 ) ) 00422 result += " " + kmkernel->acctMgr()->find( *it2 )->name(); 00423 result += "\n"; 00424 } 00425 if ( bStopProcessingHere ) 00426 result += "If it matches, processing stops at this filter.\n"; 00427 } 00428 return result; 00429 } 00430 #endif