kmail

kmfiltermgr.cpp
1// kmfiltermgr.cpp
2
3// my header
4#ifdef HAVE_CONFIG_H
5#include <config.h>
6#endif
7
8#include "kmfiltermgr.h"
9
10// other kmail headers
11#include "filterlog.h"
13#include "kmfilterdlg.h"
14#include "kmfolderindex.h"
15#include "filterimporterexporter.h"
17#include "kmfoldermgr.h"
18#include "kmmsgdict.h"
19#include "messageproperty.h"
20using KMail::MessageProperty;
21
22// other KDE headers
23#include <kdebug.h>
24#include <tdelocale.h>
25#include <tdeconfig.h>
26
27// other TQt headers
28#include <tqregexp.h>
29#include <tqvaluevector.h>
30
31// other headers
32#include <assert.h>
33
34
35//-----------------------------------------------------------------------------
36KMFilterMgr::KMFilterMgr( bool popFilter )
37 : mEditDialog( 0 ),
38 bPopFilter( popFilter ),
39 mShowLater( false ),
40 mDirtyBufferedFolderTarget( true ),
41 mBufferedFolderTarget( true ),
42 mRefCount( 0 )
43{
44 connect( kmkernel, TQ_SIGNAL( folderRemoved( KMFolder* ) ),
45 this, TQ_SLOT( slotFolderRemoved( KMFolder* ) ) );
46}
47
48
49//-----------------------------------------------------------------------------
50KMFilterMgr::~KMFilterMgr()
51{
52 deref( true );
53 writeConfig( false );
54 clear();
55}
56
57void KMFilterMgr::clear()
58{
59 mDirtyBufferedFolderTarget = true;
60 for ( TQValueListIterator<KMFilter*> it = mFilters.begin() ;
61 it != mFilters.end() ; ++it ) {
62 delete *it;
63 }
64}
65
66//-----------------------------------------------------------------------------
67void KMFilterMgr::readConfig(void)
68{
69 TDEConfig* config = KMKernel::config();
70 clear();
71
72 if (bPopFilter) {
73 TDEConfigGroupSaver saver(config, "General");
74 mShowLater = config->readNumEntry("popshowDLmsgs",0);
75 }
76 mFilters = FilterImporterExporter::readFiltersFromConfig( config, bPopFilter );
77}
78
79//-----------------------------------------------------------------------------
80void KMFilterMgr::writeConfig(bool withSync)
81{
82 TDEConfig* config = KMKernel::config();
83
84 // Now, write out the new stuff:
85 FilterImporterExporter::writeFiltersToConfig( mFilters, config, bPopFilter );
86 TDEConfigGroupSaver saver(config, "General");
87 if (bPopFilter)
88 config->writeEntry("popshowDLmsgs", mShowLater);
89
90 if (withSync) config->sync();
91}
92
93int KMFilterMgr::processPop( KMMessage * msg ) const {
94 for ( TQValueListConstIterator<KMFilter*> it = mFilters.constBegin();
95 it != mFilters.constEnd() ; ++it )
96 if ( (*it)->pattern()->matches( msg ) )
97 return (*it)->action();
98 return NoAction;
99}
100
101bool KMFilterMgr::beginFiltering(KMMsgBase *msgBase) const
102{
103 if (MessageProperty::filtering( msgBase ))
104 return false;
105 MessageProperty::setFiltering( msgBase, true );
106 MessageProperty::setFilterFolder( msgBase, 0 );
107 if ( FilterLog::instance()->isLogging() ) {
108 FilterLog::instance()->addSeparator();
109 }
110 return true;
111}
112
113int KMFilterMgr::moveMessage(KMMessage *msg) const
114{
115 if (MessageProperty::filterFolder(msg)->moveMsg( msg ) == 0) {
116 if ( kmkernel->folderIsTrash( MessageProperty::filterFolder( msg )))
117 KMFilterAction::sendMDN( msg, KMime::MDN::Deleted );
118 } else {
119 kdDebug(5006) << "KMfilterAction - couldn't move msg" << endl;
120 return 2;
121 }
122 return 0;
123}
124
125void KMFilterMgr::endFiltering(KMMsgBase *msgBase) const
126{
127 KMFolder *parent = msgBase->parent();
128 if ( parent ) {
129 if ( parent == MessageProperty::filterFolder( msgBase ) ) {
130 parent->take( parent->find( msgBase ) );
131 }
132 else if ( ! MessageProperty::filterFolder( msgBase ) ) {
133 int index = parent->find( msgBase );
134 KMMessage *msg = parent->getMsg( index );
135 parent->take( index );
136 parent->addMsgKeepUID( msg );
137 }
138 }
139 MessageProperty::setFiltering( msgBase, false );
140}
141
142int KMFilterMgr::process( KMMessage * msg, const KMFilter * filter ) {
143 if ( !msg || !filter || !beginFiltering( msg ))
144 return 1;
145 bool stopIt = false;
146 int result = 1;
147
148 if ( FilterLog::instance()->isLogging() ) {
149 TQString logText( i18n( "<b>Evaluating filter rules:</b> " ) );
150 logText.append( filter->pattern()->asString() );
151 FilterLog::instance()->add( logText, FilterLog::patternDesc );
152 }
153
154 if (filter->pattern()->matches( msg )) {
155 if ( FilterLog::instance()->isLogging() ) {
156 FilterLog::instance()->add( i18n( "<b>Filter rules have matched.</b>" ),
157 FilterLog::patternResult );
158 }
159 if (filter->execActions( msg, stopIt ) == KMFilter::CriticalError)
160 return 2;
161
162 KMFolder *folder = MessageProperty::filterFolder( msg );
163
164 endFiltering( msg );
165 if (folder) {
166 tempOpenFolder( folder );
167 result = folder->moveMsg( msg );
168 }
169 } else {
170 endFiltering( msg );
171 result = 1;
172 }
173 return result;
174}
175
176int KMFilterMgr::process( TQ_UINT32 serNum, const KMFilter *filter )
177{
178 bool stopIt = false;
179 int result = 1;
180
181 if ( !filter )
182 return 1;
183
184 if ( isMatching( serNum, filter ) ) {
185 KMFolder *folder = 0;
186 int idx = -1;
187 // get the message with the serNum
188 KMMsgDict::instance()->getLocation( serNum, &folder, &idx );
189 if ( !folder || ( idx == -1 ) || ( idx >= folder->count() ) ) {
190 return 1;
191 }
192 KMFolderOpener openFolder(folder, "filtermgr");
193 KMMsgBase *msgBase = folder->getMsgBase( idx );
194 bool unGet = !msgBase->isMessage();
195 KMMessage *msg = folder->getMsg( idx );
196 // do the actual filtering stuff
197 if ( !msg || !beginFiltering( msg ) ) {
198 if ( unGet )
199 folder->unGetMsg( idx );
200 return 1;
201 }
202 if ( filter->execActions( msg, stopIt ) == KMFilter::CriticalError ) {
203 if ( unGet )
204 folder->unGetMsg( idx );
205 return 2;
206 }
207
208 KMFolder *targetFolder = MessageProperty::filterFolder( msg );
209
210 endFiltering( msg );
211 if ( targetFolder ) {
212 tempOpenFolder( targetFolder );
213 msg->setTransferInProgress( false );
214 result = targetFolder->moveMsg( msg );
215 msg->setTransferInProgress( true );
216 }
217 if ( unGet )
218 folder->unGetMsg( idx );
219 } else {
220 result = 1;
221 }
222 return result;
223}
224
225int KMFilterMgr::process( KMMessage * msg, FilterSet set,
226 bool account, uint accountId ) {
227 if ( bPopFilter )
228 return processPop( msg );
229
230 if ( set == NoSet ) {
231 kdDebug(5006) << "KMFilterMgr: process() called with not filter set selected"
232 << endl;
233 return 1;
234 }
235
236 bool stopIt = false;
237 bool atLeastOneRuleMatched = false;
238
239 if (!beginFiltering( msg ))
240 return 1;
241 for ( TQValueListConstIterator<KMFilter*> it = mFilters.constBegin();
242 !stopIt && it != mFilters.constEnd() ; ++it ) {
243
244 if ( ( ( (set&Inbound) && (*it)->applyOnInbound() ) &&
245 ( !account ||
246 ( account && (*it)->applyOnAccount( accountId ) ) ) ) ||
247 ( (set&Outbound) && (*it)->applyOnOutbound() ) ||
248 ( (set&Explicit) && (*it)->applyOnExplicit() ) ) {
249 // filter is applicable
250
251 if ( FilterLog::instance()->isLogging() ) {
252 TQString logText( i18n( "<b>Evaluating filter rules:</b> " ) );
253 logText.append( (*it)->pattern()->asString() );
254 FilterLog::instance()->add( logText, FilterLog::patternDesc );
255 }
256 if ( (*it)->pattern()->matches( msg ) ) {
257 // filter matches
258 if ( FilterLog::instance()->isLogging() ) {
259 FilterLog::instance()->add( i18n( "<b>Filter rules have matched.</b>" ),
260 FilterLog::patternResult );
261 }
262 atLeastOneRuleMatched = true;
263 // execute actions:
264 if ( (*it)->execActions(msg, stopIt) == KMFilter::CriticalError )
265 return 2;
266 }
267 }
268 }
269
270 KMFolder *folder = MessageProperty::filterFolder( msg );
271 /* endFilter does a take() and addButKeepUID() to ensure the changed
272 * message is on disk. This is unnessecary if nothing matched, so just
273 * reset state and don't update the listview at all. */
274 if ( atLeastOneRuleMatched )
275 endFiltering( msg );
276 else
277 MessageProperty::setFiltering( msg, false );
278 if (folder) {
279 tempOpenFolder( folder );
280 folder->moveMsg(msg);
281 return 0;
282 }
283 return 1;
284}
285
286bool KMFilterMgr::isMatching( TQ_UINT32 serNum, const KMFilter *filter )
287{
288 bool result = false;
289 if ( FilterLog::instance()->isLogging() ) {
290 TQString logText( i18n( "<b>Evaluating filter rules:</b> " ) );
291 logText.append( filter->pattern()->asString() );
292 FilterLog::instance()->add( logText, FilterLog::patternDesc );
293 }
294 if ( filter->pattern()->matches( serNum ) ) {
295 if ( FilterLog::instance()->isLogging() ) {
296 FilterLog::instance()->add( i18n( "<b>Filter rules have matched.</b>" ),
297 FilterLog::patternResult );
298 }
299 result = true;
300 }
301 return result;
302}
303
304bool KMFilterMgr::atLeastOneFilterAppliesTo( unsigned int accountID ) const
305{
306 TQValueListConstIterator<KMFilter*> it = mFilters.constBegin();
307 for ( ; it != mFilters.constEnd() ; ++it ) {
308 if ( (*it)->applyOnAccount( accountID ) ) {
309 return true;
310 }
311 }
312 return false;
313}
314
315bool KMFilterMgr::atLeastOneIncomingFilterAppliesTo( unsigned int accountID ) const
316{
317 TQValueListConstIterator<KMFilter*> it = mFilters.constBegin();
318 for ( ; it != mFilters.constEnd() ; ++it ) {
319 if ( (*it)->applyOnInbound() && (*it)->applyOnAccount( accountID ) ) {
320 return true;
321 }
322 }
323 return false;
324}
325
326bool KMFilterMgr::atLeastOneOnlineImapFolderTarget()
327{
328 if (!mDirtyBufferedFolderTarget)
329 return mBufferedFolderTarget;
330
331 mDirtyBufferedFolderTarget = false;
332
333 TQValueListConstIterator<KMFilter*> it = mFilters.constBegin();
334 for ( ; it != mFilters.constEnd() ; ++it ) {
335 KMFilter *filter = *it;
336 TQPtrListIterator<KMFilterAction> jt( *filter->actions() );
337 for ( jt.toFirst() ; jt.current() ; ++jt ) {
338 KMFilterActionWithFolder *f = dynamic_cast<KMFilterActionWithFolder*>(*jt);
339 if (!f)
340 continue;
341 TQString name = f->argsAsString();
342 KMFolder *folder = kmkernel->imapFolderMgr()->findIdString( name );
343 if (folder) {
344 mBufferedFolderTarget = true;
345 return true;
346 }
347 }
348 }
349 mBufferedFolderTarget = false;
350 return false;
351}
352
353//-----------------------------------------------------------------------------
354void KMFilterMgr::ref(void)
355{
356 mRefCount++;
357}
358
359//-----------------------------------------------------------------------------
360void KMFilterMgr::deref(bool force)
361{
362 if (!force)
363 mRefCount--;
364 if (mRefCount < 0)
365 mRefCount = 0;
366 if (mRefCount && !force)
367 return;
368 TQValueVector< KMFolder *>::const_iterator it;
369 for ( it = mOpenFolders.constBegin(); it != mOpenFolders.constEnd(); ++it )
370 (*it)->close("filtermgr");
371 mOpenFolders.clear();
372}
373
374
375//-----------------------------------------------------------------------------
376int KMFilterMgr::tempOpenFolder(KMFolder* aFolder)
377{
378 assert( aFolder );
379
380 int rc = aFolder->open("filermgr");
381 if (rc) return rc;
382
383 mOpenFolders.append( aFolder );
384 return 0;
385}
386
387
388//-----------------------------------------------------------------------------
389void KMFilterMgr::openDialog( TQWidget *, bool checkForEmptyFilterList )
390{
391 if( !mEditDialog )
392 {
393 //
394 // We can't use the parent as long as the dialog is modeless
395 // and there is one shared dialog for all top level windows.
396 //
397 mEditDialog = new KMFilterDlg( 0, "filterdialog", bPopFilter,
398 checkForEmptyFilterList );
399 }
400 mEditDialog->show();
401}
402
403
404//-----------------------------------------------------------------------------
405void KMFilterMgr::createFilter( const TQCString & field, const TQString & value )
406{
407 openDialog( 0, false );
408 mEditDialog->createFilter( field, value );
409}
410
411
412//-----------------------------------------------------------------------------
413const TQString KMFilterMgr::createUniqueName( const TQString & name )
414{
415 TQString uniqueName = name;
416 int counter = 0;
417 bool found = true;
418
419 while ( found ) {
420 found = false;
421 for ( TQValueListConstIterator<KMFilter*> it = mFilters.constBegin();
422 it != mFilters.constEnd(); ++it ) {
423 if ( !( (*it)->name().compare( uniqueName ) ) ) {
424 found = true;
425 ++counter;
426 uniqueName = name;
427 uniqueName += TQString( " (" ) + TQString::number( counter )
428 + TQString( ")" );
429 break;
430 }
431 }
432 }
433 return uniqueName;
434}
435
436
437//-----------------------------------------------------------------------------
438void KMFilterMgr::appendFilters( const TQValueList<KMFilter*> &filters,
439 bool replaceIfNameExists )
440{
441 mDirtyBufferedFolderTarget = true;
442 beginUpdate();
443 if ( replaceIfNameExists ) {
444 TQValueListConstIterator<KMFilter*> it1 = filters.constBegin();
445 for ( ; it1 != filters.constEnd() ; ++it1 ) {
446 TQValueListConstIterator<KMFilter*> it2 = mFilters.constBegin();
447 for ( ; it2 != mFilters.constEnd() ; ++it2 ) {
448 if ( (*it1)->name() == (*it2)->name() ) {
449 mFilters.remove( (*it2) );
450 it2 = mFilters.constBegin();
451 }
452 }
453 }
454 }
455 mFilters += filters;
456 writeConfig( true );
457 endUpdate();
458}
459
460void KMFilterMgr::setFilters( const TQValueList<KMFilter*> &filters )
461{
462 beginUpdate();
463 clear();
464 mFilters = filters;
465 writeConfig( true );
466 endUpdate();
467}
468
469void KMFilterMgr::slotFolderRemoved( KMFolder * aFolder )
470{
471 folderRemoved( aFolder, 0 );
472}
473
474//-----------------------------------------------------------------------------
475bool KMFilterMgr::folderRemoved(KMFolder* aFolder, KMFolder* aNewFolder)
476{
477 mDirtyBufferedFolderTarget = true;
478 bool rem = false;
479 TQValueListConstIterator<KMFilter*> it = mFilters.constBegin();
480 for ( ; it != mFilters.constEnd() ; ++it )
481 if ( (*it)->folderRemoved(aFolder, aNewFolder) )
482 rem = true;
483
484 return rem;
485}
486
487
488//-----------------------------------------------------------------------------
489#ifndef NDEBUG
490void KMFilterMgr::dump(void) const
491{
492
493 TQValueListConstIterator<KMFilter*> it = mFilters.constBegin();
494 for ( ; it != mFilters.constEnd() ; ++it ) {
495 kdDebug(5006) << (*it)->asString() << endl;
496 }
497}
498#endif
499
500//-----------------------------------------------------------------------------
501void KMFilterMgr::endUpdate(void)
502{
503 emit filterListUpdated();
504}
505
506#include "kmfiltermgr.moc"
Abstract base class for KMail's filter actions that need a mail folder as parameter,...
virtual const TQString argsAsString() const
Return extra arguments as string.
static void sendMDN(KMMessage *msg, KMime::MDN::DispositionType d, const TQValueList< KMime::MDN::DispositionModifier > &m=TQValueList< KMime::MDN::DispositionModifier >())
Automates the sending of MDNs from filter actions.
The filter dialog.
Definition: kmfilterdlg.h:340
RAII for KMFolder::open() / close().
Definition: kmfolder.h:688
Mail folder.
Definition: kmfolder.h:69
int moveMsg(KMMessage *msg, int *index_return=0)
Detaches the given message from it's current folder and adds it to this folder.
Definition: kmfolder.cpp:425
int addMsgKeepUID(KMMessage *msg, int *index_return=0)
(Note(bo): This needs to be fixed better at a later point.) This is overridden by dIMAP because addMs...
Definition: kmfolder.cpp:395
KMMsgInfo * unGetMsg(int idx)
Replace KMMessage with KMMsgInfo and delete KMMessage
Definition: kmfolder.cpp:326
KMMessage * take(int idx)
Detach message from this folder.
Definition: kmfolder.cpp:380
KMMessage * getMsg(int idx)
Read message at given index.
Definition: kmfolder.cpp:321
const KMMsgBase * getMsgBase(int idx) const
Provides access to the basic message fields that are also stored in the index.
Definition: kmfolder.cpp:360
int count(bool cache=false) const
Number of messages in this folder.
Definition: kmfolder.cpp:445
int open(const char *owner)
Open folder for access.
Definition: kmfolder.cpp:479
int find(const KMMsgBase *msg) const
Returns the index of the given message or -1 if not found.
Definition: kmfolder.cpp:435
This is a Mime Message.
Definition: kmmessage.h:68
void setTransferInProgress(bool value, bool force=false)
Set that the message shall not be deleted because it is still required.
Definition: kmmessage.cpp:243
void getLocation(unsigned long key, KMFolder **retFolder, int *retIndex) const
Returns the folder the message represented by the serial number key is in and the index in that folde...
Definition: kmmsgdict.cpp:319
static const KMMsgDict * instance()
Access the globally unique MessageDict.
Definition: kmmsgdict.cpp:167
Utility class that provides persisting of filters to/from TDEConfig.
KMail Filter Log Collector.
Definition: filterlog.h:54