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"
12 using KMail::FilterLog;
13 #include "kmfilterdlg.h"
14 #include "kmfolderindex.h"
15 #include "filterimporterexporter.h"
17 #include "kmfoldermgr.h"
18 #include "kmmsgdict.h"
19 #include "messageproperty.h"
20 using 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 //-----------------------------------------------------------------------------
36 KMFilterMgr::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 //-----------------------------------------------------------------------------
50 KMFilterMgr::~KMFilterMgr()
51 {
52  deref( true );
53  writeConfig( false );
54  clear();
55 }
56 
57 void 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 //-----------------------------------------------------------------------------
67 void 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 //-----------------------------------------------------------------------------
80 void 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 
93 int 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 
101 bool 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 
113 int 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 
125 void 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 
142 int 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 
176 int 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 
225 int 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 
286 bool 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 
304 bool 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 
315 bool 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 
326 bool 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 //-----------------------------------------------------------------------------
354 void KMFilterMgr::ref(void)
355 {
356  mRefCount++;
357 }
358 
359 //-----------------------------------------------------------------------------
360 void 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 //-----------------------------------------------------------------------------
376 int 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 //-----------------------------------------------------------------------------
389 void 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 //-----------------------------------------------------------------------------
405 void KMFilterMgr::createFilter( const TQCString & field, const TQString & value )
406 {
407  openDialog( 0, false );
408  mEditDialog->createFilter( field, value );
409 }
410 
411 
412 //-----------------------------------------------------------------------------
413 const 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 //-----------------------------------------------------------------------------
438 void 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 
460 void KMFilterMgr::setFilters( const TQValueList<KMFilter*> &filters )
461 {
462  beginUpdate();
463  clear();
464  mFilters = filters;
465  writeConfig( true );
466  endUpdate();
467 }
468 
469 void KMFilterMgr::slotFolderRemoved( KMFolder * aFolder )
470 {
471  folderRemoved( aFolder, 0 );
472 }
473 
474 //-----------------------------------------------------------------------------
475 bool 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
490 void 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 //-----------------------------------------------------------------------------
501 void 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