kmail

index.cpp
1 /* This file is part of KMail
2  * Copyright (C) 2005 Luís Pedro Coelho <luis@luispedro.org>
3  *
4  * KMail is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License, version 2, as
6  * published by the Free Software Foundation.
7  *
8  * KMail is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16  *
17  * In addition, as a special exception, the copyright holders give
18  * permission to link the code of this program with any edition of
19  * the TQt library by Trolltech AS, Norway (or with modified versions
20  * of TQt that use the same license as TQt), and distribute linked
21  * combinations including the two. You must obey the GNU General
22  * Public License in all respects for all of the code used other than
23  * TQt. If you modify this file, you may extend this exception to
24  * your version of the file, but you are not obligated to do so. If
25  * you do not wish to do so, delete this exception statement from
26  * your version.
27  */
28 
29 #include "index.h"
30 
31 #include "kmkernel.h"
32 #include "kmfoldermgr.h"
33 #include "kmmsgdict.h"
34 #include "kmfolder.h"
35 #include "kmsearchpattern.h"
36 #include "kmfoldersearch.h"
37 
38 #include <kdebug.h>
39 #include <tdeapplication.h>
40 #include <tqfile.h>
41 #include <tqtimer.h>
42 #include <tqvaluestack.h>
43 #include <tqptrlist.h>
44 #include <tqfileinfo.h>
45 #ifdef HAVE_INDEXLIB
46 #include <indexlib/create.h>
47 #endif
48 
49 #include <sys/types.h>
50 #include <sys/stat.h>
51 
52 #include <iostream>
53 #include <algorithm>
54 #include <cstdlib>
55 
56 namespace {
57 const unsigned int MaintenanceLimit = 1000;
58 const char* const folderIndexDisabledKey = "fulltextIndexDisabled";
59 }
60 
61 #ifdef HAVE_INDEXLIB
62 static
63 TQValueList<int> vectorToTQValueList( const std::vector<TQ_UINT32>& input ) {
64  TQValueList<int> res;
65  std::copy( input.begin(), input.end(), std::back_inserter( res ) );
66  return res;
67 }
68 
69 static
70 std::vector<TQ_UINT32> TQValueListToVector( const TQValueList<int>& input ) {
71  std::vector<TQ_UINT32> res;
72  // res.assign( input.begin(), input.end() ) doesn't work for some reason
73  for ( TQValueList<int>::const_iterator first = input.begin(), past = input.end(); first != past; ++first ) {
74  res.push_back( *first );
75  }
76  return res;
77 }
78 #endif
79 
80 KMMsgIndex::KMMsgIndex( TQObject* parent ):
81  TQObject( parent, "index" ),
82  mState( s_idle ),
83 #ifdef HAVE_INDEXLIB
84  mLockFile( std::string( static_cast<const char*>( TQFile::encodeName( defaultPath() ) + "/lock" ) ) ),
85  mIndex( 0 ),
86 #endif
87  mIndexPath( TQFile::encodeName( defaultPath() ) ),
88  mTimer( new TQTimer( this, "mTimer" ) ),
89  //mSyncState( ss_none ),
90  //mSyncTimer( new TQTimer( this ) ),
91  mSlowDown( false ) {
92  kdDebug( 5006 ) << "KMMsgIndex::KMMsgIndex()" << endl;
93 
94  connect( kmkernel->folderMgr(), TQ_SIGNAL( msgRemoved( KMFolder*, TQ_UINT32 ) ), TQ_SLOT( slotRemoveMessage( KMFolder*, TQ_UINT32 ) ) );
95  connect( kmkernel->folderMgr(), TQ_SIGNAL( msgAdded( KMFolder*, TQ_UINT32 ) ), TQ_SLOT( slotAddMessage( KMFolder*, TQ_UINT32 ) ) );
96  connect( kmkernel->dimapFolderMgr(), TQ_SIGNAL( msgRemoved( KMFolder*, TQ_UINT32 ) ), TQ_SLOT( slotRemoveMessage( KMFolder*, TQ_UINT32 ) ) );
97  connect( kmkernel->dimapFolderMgr(), TQ_SIGNAL( msgAdded( KMFolder*, TQ_UINT32 ) ), TQ_SLOT( slotAddMessage( KMFolder*, TQ_UINT32 ) ) );
98 
99  connect( mTimer, TQ_SIGNAL( timeout() ), TQ_SLOT( act() ) );
100  //connect( mSyncTimer, TQ_SIGNAL( timeout() ), TQ_SLOT( syncIndex() ) );
101 
102 #ifdef HAVE_INDEXLIB
103  TDEConfigGroup cfg( KMKernel::config(), "text-index" );
104  if ( !cfg.readBoolEntry( "enabled", false ) ) {
105  indexlib::remove( mIndexPath );
106  mLockFile.force_unlock();
107  mState = s_disabled;
108  return;
109  }
110  if ( !mLockFile.trylock() ) {
111  indexlib::remove( mIndexPath );
112 
113  mLockFile.force_unlock();
114  mLockFile.trylock();
115  } else {
116  mIndex = indexlib::open( mIndexPath, indexlib::open_flags::fail_if_nonexistant ).release();
117  }
118  if ( !mIndex ) {
119  TQTimer::singleShot( 8000, this, TQ_SLOT( create() ) );
120  mState = s_willcreate;
121  } else {
122  if ( cfg.readBoolEntry( "creating" ) ) {
123  TQTimer::singleShot( 8000, this, TQ_SLOT( continueCreation() ) );
124  mState = s_creating;
125  } else {
126  mPendingMsgs = TQValueListToVector( cfg.readIntListEntry( "pending" ) );
127  mRemovedMsgs = TQValueListToVector( cfg.readIntListEntry( "removed" ) );
128  }
129  }
130  mIndex = 0;
131 #else
132  mState = s_error;
133 #endif
134  //if ( mState == s_idle ) mSyncState = ss_synced;
135 }
136 
137 
138 KMMsgIndex::~KMMsgIndex() {
139  kdDebug( 5006 ) << "KMMsgIndex::~KMMsgIndex()" << endl;
140 #ifdef HAVE_INDEXLIB
141  TDEConfigGroup cfg( KMKernel::config(), "text-index" );
142  cfg.writeEntry( "creating", mState == s_creating );
143  TQValueList<int> pendingMsg;
144  if ( mState == s_processing ) {
145  Q_ASSERT( mAddedMsgs.empty() );
146  pendingMsg = vectorToTQValueList( mPendingMsgs );
147  }
148  cfg.writeEntry( "pending", pendingMsg );
149  cfg.writeEntry( "removed", vectorToTQValueList( mRemovedMsgs ) );
150  delete mIndex;
151 #endif
152 }
153 
154 bool KMMsgIndex::isIndexable( KMFolder* folder ) const {
155  if ( !folder || !folder->parent() ) return false;
156  const KMFolderMgr* manager = folder->parent()->manager();
157  return manager == kmkernel->folderMgr() || manager == kmkernel->dimapFolderMgr();
158 }
159 
160 bool KMMsgIndex::isIndexed( KMFolder* folder ) const {
161  if ( !isIndexable( folder ) ) return false;
162  TDEConfig* config = KMKernel::config();
163  TDEConfigGroupSaver saver( config, "Folder-" + folder->idString() );
164  return !config->readBoolEntry( folderIndexDisabledKey, false );
165 }
166 
167 void KMMsgIndex::setEnabled( bool e ) {
168  kdDebug( 5006 ) << "KMMsgIndex::setEnabled( " << e << " )" << endl;
169  TDEConfig* config = KMKernel::config();
170  TDEConfigGroupSaver saver( config, "text-index" );
171  if ( config->readBoolEntry( "enabled", !e ) == e ) return;
172  config->writeEntry( "enabled", e );
173  if ( e ) {
174  switch ( mState ) {
175  case s_idle:
176  case s_willcreate:
177  case s_creating:
178  case s_processing:
179  // nothing to do
180  return;
181  case s_error:
182  // nothing can be done, probably
183  return;
184  case s_disabled:
185  TQTimer::singleShot( 8000, this, TQ_SLOT( create() ) );
186  mState = s_willcreate;
187  }
188  } else {
189  clear();
190  }
191 }
192 
193 void KMMsgIndex::setIndexingEnabled( KMFolder* folder, bool e ) {
194  TDEConfig* config = KMKernel::config();
195  TDEConfigGroupSaver saver( config, "Folder-" + folder->idString() );
196  if ( config->readBoolEntry( folderIndexDisabledKey, e ) == e ) return; // nothing to do
197  config->writeEntry( folderIndexDisabledKey, e );
198 
199  if ( e ) {
200  switch ( mState ) {
201  case s_idle:
202  case s_creating:
203  case s_processing:
204  mPendingFolders.push_back( folder );
205  scheduleAction();
206  break;
207  case s_willcreate:
208  // do nothing, create() will handle this
209  break;
210  case s_error:
211  case s_disabled:
212  // nothing can be done
213  break;
214  }
215 
216  } else {
217  switch ( mState ) {
218  case s_willcreate:
219  // create() will notice that folder is disabled
220  break;
221  case s_creating:
222  if ( std::find( mPendingFolders.begin(), mPendingFolders.end(), folder ) != mPendingFolders.end() ) {
223  // easy:
224  mPendingFolders.erase( std::find( mPendingFolders.begin(), mPendingFolders.end(), folder ) );
225  break;
226  }
227  //else fall-through
228  case s_idle:
229  case s_processing:
230 
231  case s_error:
232  case s_disabled:
233  // nothing can be done
234  break;
235  }
236  }
237 }
238 
239 void KMMsgIndex::clear() {
240  kdDebug( 5006 ) << "KMMsgIndex::clear()" << endl;
241 #ifdef HAVE_INDEXLIB
242  delete mIndex;
243  mLockFile.force_unlock();
244  mIndex = 0;
245  indexlib::remove( mIndexPath );
246  mPendingMsgs.clear();
247  mPendingFolders.clear();
248  mMaintenanceCount = 0;
249  mAddedMsgs.clear();
250  mRemovedMsgs.clear();
251  mExisting.clear();
252  mState = s_disabled;
253  for ( std::set<KMFolder*>::const_iterator first = mOpenedFolders.begin(), past = mOpenedFolders.end(); first != past; ++first ) {
254  ( *first )->close("msgindex");
255  }
256  mOpenedFolders.clear();
257  for ( std::vector<Search*>::const_iterator first = mSearches.begin(), past = mSearches.end(); first != past; ++first ) {
258  delete *first;
259  }
260  mSearches.clear();
261  mTimer->stop();
262 #endif
263 }
264 
265 void KMMsgIndex::maintenance() {
266 #ifdef HAVE_INDEXLIB
267  if ( mState != s_idle || kapp->hasPendingEvents() ) {
268  TQTimer::singleShot( 8000, this, TQ_SLOT( maintenance() ) );
269  return;
270  }
271  mIndex->maintenance();
272 #endif
273 }
274 
275 int KMMsgIndex::addMessage( TQ_UINT32 serNum ) {
276  kdDebug( 5006 ) << "KMMsgIndex::addMessage( " << serNum << " )" << endl;
277  if ( mState == s_error ) return 0;
278 #ifdef HAVE_INDEXLIB
279  assert( mIndex );
280  if ( !mExisting.empty() && std::binary_search( mExisting.begin(), mExisting.end(), serNum ) ) return 0;
281 
282  int idx = -1;
283  KMFolder* folder = 0;
284  KMMsgDict::instance()->getLocation( serNum, &folder, &idx );
285  if ( !folder || idx == -1 ) return -1;
286  if ( !mOpenedFolders.count( folder ) ) {
287  mOpenedFolders.insert( folder );
288  folder->open("msgindex");
289  }
290  KMMessage* msg = folder->getMsg( idx );
291  /* I still don't know whether we should allow decryption or not.
292  * Setting to false which makes more sense.
293  * We keep signature to get the person's name
294  */
295  TQString body = msg->asPlainText( false, false );
296  if ( !body.isEmpty() && static_cast<const char*>( body.latin1() ) ) {
297  mIndex->add( body.latin1(), TQString::number( serNum ).latin1() );
298  } else {
299  kdDebug( 5006 ) << "Funny, no body" << endl;
300  }
301  folder->unGetMsg( idx );
302 #endif
303  return 0;
304 }
305 
306 void KMMsgIndex::act() {
307  kdDebug( 5006 ) << "KMMsgIndex::act()" << endl;
308  if ( kapp->hasPendingEvents() ) {
309  //nah, some other time..
310  mTimer->start( 500 );
311  mSlowDown = true;
312  return;
313  }
314  if ( mSlowDown ) {
315  mSlowDown = false;
316  mTimer->start( 0 );
317  }
318  if ( !mPendingMsgs.empty() ) {
319  addMessage( mPendingMsgs.back() );
320  mPendingMsgs.pop_back();
321  return;
322  }
323  if ( !mPendingFolders.empty() ) {
324  KMFolder *f = mPendingFolders.back();
325  mPendingFolders.pop_back();
326  if ( !mOpenedFolders.count( f ) ) {
327  mOpenedFolders.insert( f );
328  f->open("msgindex");
329  }
330  const KMMsgDict* dict = KMMsgDict::instance();
331  TDEConfig* config = KMKernel::config();
332  TDEConfigGroupSaver saver( config, "Folder-" + f->idString() );
333  if ( config->readBoolEntry( folderIndexDisabledKey, true ) ) {
334  for ( int i = 0; i < f->count(); ++i ) {
335  mPendingMsgs.push_back( dict->getMsgSerNum( f, i ) );
336  }
337  }
338  return;
339  }
340  if ( !mAddedMsgs.empty() ) {
341  std::swap( mAddedMsgs, mPendingMsgs );
342  mState = s_processing;
343  return;
344  }
345  for ( std::set<KMFolder*>::const_iterator first = mOpenedFolders.begin(), past = mOpenedFolders.end();
346  first != past;
347  ++first ) {
348  ( *first )->close("msgindex");
349  }
350  mOpenedFolders.clear();
351  mState = s_idle;
352  mTimer->stop();
353 }
354 
355 void KMMsgIndex::continueCreation() {
356  kdDebug( 5006 ) << "KMMsgIndex::continueCreation()" << endl;
357 #ifdef HAVE_INDEXLIB
358  create();
359  unsigned count = mIndex->ndocs();
360  mExisting.clear();
361  mExisting.reserve( count );
362  for ( unsigned i = 0; i != count; ++i ) {
363  mExisting.push_back( std::atoi( mIndex->lookup_docname( i ).c_str() ) );
364  }
365  std::sort( mExisting.begin(), mExisting.end() );
366 #endif
367 }
368 
369 void KMMsgIndex::create() {
370  kdDebug( 5006 ) << "KMMsgIndex::create()" << endl;
371 
372 #ifdef HAVE_INDEXLIB
373  if ( !TQFileInfo( mIndexPath ).exists() ) {
374  ::mkdir( mIndexPath, S_IRWXU );
375  }
376  mState = s_creating;
377  if ( !mIndex ) mIndex = indexlib::create( mIndexPath ).release();
378  if ( !mIndex ) {
379  kdDebug( 5006 ) << "Error creating index" << endl;
380  mState = s_error;
381  return;
382  }
383  TQValueStack<KMFolderDir*> folders;
384  folders.push(&(kmkernel->folderMgr()->dir()));
385  folders.push(&(kmkernel->dimapFolderMgr()->dir()));
386  while ( !folders.empty() ) {
387  KMFolderDir *dir = folders.pop();
388  for(KMFolderNode *child = dir->first(); child; child = dir->next()) {
389  if ( child->isDir() )
390  folders.push((KMFolderDir*)child);
391  else
392  mPendingFolders.push_back( (KMFolder*)child );
393  }
394  }
395  mTimer->start( 4000 ); // wait a couple of seconds before starting up...
396  mSlowDown = true;
397 #endif
398 }
399 
400 bool KMMsgIndex::startQuery( KMSearch* s ) {
401  kdDebug( 5006 ) << "KMMsgIndex::startQuery( . )" << endl;
402  if ( mState != s_idle ) return false;
403  if ( !isIndexed( s->root() ) || !canHandleQuery( s->searchPattern() ) ) return false;
404 
405  kdDebug( 5006 ) << "KMMsgIndex::startQuery( . ) starting query" << endl;
406  Search* search = new Search( s );
407  connect( search, TQ_SIGNAL( finished( bool ) ), s, TQ_SIGNAL( finished( bool ) ) );
408  connect( search, TQ_SIGNAL( finished( bool ) ), s, TQ_SLOT( indexFinished() ) );
409  connect( search, TQ_SIGNAL( destroyed( TQObject* ) ), TQ_SLOT( removeSearch( TQObject* ) ) );
410  connect( search, TQ_SIGNAL( found( TQ_UINT32 ) ), s, TQ_SIGNAL( found( TQ_UINT32 ) ) );
411  mSearches.push_back( search );
412  return true;
413 }
414 
415 
416 //void KMMsgIndex::startSync() {
417 // switch ( mSyncState ) {
418 // case ss_none:
419 // mIndex->start_sync();
420 // mSyncState = ss_started;
421 // mSyncTimer.start( 4000, true );
422 // break;
423 // case ss_started:
424 // mIndex->sync_now();
425 // mSyncState = ss_synced;
426 // mLockFile.unlock();
427 // break;
428 // }
429 //}
430 //
431 //void KMMsgIndex::finishSync() {
432 //
433 //}
434 
435 void KMMsgIndex::removeSearch( TQObject* destroyed ) {
436  mSearches.erase( std::find( mSearches.begin(), mSearches.end(), destroyed ) );
437 }
438 
439 
440 bool KMMsgIndex::stopQuery( KMSearch* s ) {
441  kdDebug( 5006 ) << "KMMsgIndex::stopQuery( . )" << endl;
442  for ( std::vector<Search*>::iterator iter = mSearches.begin(), past = mSearches.end(); iter != past; ++iter ) {
443  if ( ( *iter )->search() == s ) {
444  delete *iter;
445  mSearches.erase( iter );
446  return true;
447  }
448  }
449  return false;
450 }
451 
452 std::vector<TQ_UINT32> KMMsgIndex::simpleSearch( TQString s, bool* ok ) const {
453  kdDebug( 5006 ) << "KMMsgIndex::simpleSearch( -" << s.latin1() << "- )" << endl;
454  if ( mState == s_error || mState == s_disabled ) {
455  if ( ok ) *ok = false;
456  return std::vector<TQ_UINT32>();
457  }
458  std::vector<TQ_UINT32> res;
459 #ifdef HAVE_INDEXLIB
460  assert( mIndex );
461  std::vector<unsigned> residx = mIndex->search( s.latin1() )->list();
462  res.reserve( residx.size() );
463  for ( std::vector<unsigned>::const_iterator first = residx.begin(), past = residx.end();first != past; ++first ) {
464  res.push_back( std::atoi( mIndex->lookup_docname( *first ).c_str() ) );
465  }
466  if ( ok ) *ok = true;
467 #endif
468  return res;
469 }
470 
471 bool KMMsgIndex::canHandleQuery( const KMSearchPattern* pat ) const {
472  kdDebug( 5006 ) << "KMMsgIndex::canHandleQuery( . )" << endl;
473  if ( !pat ) return false;
474  TQPtrListIterator<KMSearchRule> it( *pat );
475  KMSearchRule* rule;
476  while ( (rule = it.current()) != 0 ) {
477  ++it;
478  if ( !rule->field().isEmpty() && !rule->contents().isEmpty() &&
479  rule->function() == KMSearchRule::FuncContains &&
480  rule->field() == "<body>" ) return true;
481  }
482  return false;
483 }
484 
485 void KMMsgIndex::slotAddMessage( KMFolder*, TQ_UINT32 serNum ) {
486  kdDebug( 5006 ) << "KMMsgIndex::slotAddMessage( . , " << serNum << " )" << endl;
487  if ( mState == s_error || mState == s_disabled ) return;
488 
489  if ( mState == s_creating ) mAddedMsgs.push_back( serNum );
490  else mPendingMsgs.push_back( serNum );
491 
492  if ( mState == s_idle ) mState = s_processing;
493  scheduleAction();
494 }
495 
496 void KMMsgIndex::slotRemoveMessage( KMFolder*, TQ_UINT32 serNum ) {
497  kdDebug( 5006 ) << "KMMsgIndex::slotRemoveMessage( . , " << serNum << " )" << endl;
498  if ( mState == s_error || mState == s_disabled ) return;
499 
500  if ( mState == s_idle ) mState = s_processing;
501  mRemovedMsgs.push_back( serNum );
502  scheduleAction();
503 }
504 
505 void KMMsgIndex::scheduleAction() {
506 #ifdef HAVE_INDEXLIB
507  if ( mState == s_willcreate || !mIndex ) return;
508  if ( !mSlowDown ) mTimer->start( 0 );
509 #endif
510 }
511 
512 void KMMsgIndex::removeMessage( TQ_UINT32 serNum ) {
513  kdDebug( 5006 ) << "KMMsgIndex::removeMessage( " << serNum << " )" << endl;
514  if ( mState == s_error || mState == s_disabled ) return;
515 
516 #ifdef HAVE_INDEXLIB
517  mIndex->remove_doc( TQString::number( serNum ).latin1() );
518  ++mMaintenanceCount;
519  if ( mMaintenanceCount > MaintenanceLimit && mRemovedMsgs.empty() ) {
520  TQTimer::singleShot( 100, this, TQ_SLOT( maintenance() ) );
521  }
522 #endif
523 }
524 
525 TQString KMMsgIndex::defaultPath() {
526  return KMKernel::localDataPath() + "text-index";
527 }
528 
529 bool KMMsgIndex::creating() const {
530  return !mPendingMsgs.empty() || !mPendingFolders.empty();
531 }
532 
533 KMMsgIndex::Search::Search( KMSearch* s ):
534  mSearch( s ),
535  mTimer( new TQTimer( this, "mTimer" ) ),
536  mResidual( new KMSearchPattern ),
537  mState( s_starting ) {
538  connect( mTimer, TQ_SIGNAL( timeout() ), TQ_SLOT( act() ) );
539  mTimer->start( 0 );
540 }
541 
542 KMMsgIndex::Search::~Search() {
543  delete mTimer;
544 }
545 
546 void KMMsgIndex::Search::act() {
547  switch ( mState ) {
548  case s_starting: {
549  KMSearchPattern* pat = mSearch->searchPattern();
550  TQString terms;
551  for ( KMSearchRule* rule = pat->first(); rule; rule = pat->next() ) {
552  Q_ASSERT( rule->function() == KMSearchRule::FuncContains );
553  terms += TQString::fromLatin1( " %1 " ).arg( rule->contents() );
554  }
555 
556  mValues = kmkernel->msgIndex()->simpleSearch( terms, 0 );
557  break;
558  }
559  case s_emitstopped:
560  mTimer->start( 0 );
561  mState = s_emitting;
562  // fall throu
563  case s_emitting:
564  if ( kapp->hasPendingEvents() ) {
565  //nah, some other time..
566  mTimer->start( 250 );
567  mState = s_emitstopped;
568  return;
569  }
570  for ( int i = 0; i != 16 && !mValues.empty(); ++i ) {
571  KMFolder* folder;
572  int index;
573  KMMsgDict::instance()->getLocation( mValues.back(), &folder, &index );
574  if ( folder &&
575  mSearch->inScope( folder ) &&
576  ( !mResidual || mResidual->matches( mValues.back() ) ) ) {
577 
578  emit found( mValues.back() );
579  }
580  mValues.pop_back();
581  }
582  if ( mValues.empty() ) {
583  emit finished( true );
584  mState = s_done;
585  mTimer->stop();
586  delete this;
587  }
588  break;
589  default:
590  Q_ASSERT( 0 );
591  }
592 }
593 #include "index.moc"
594 
KMail list that manages the contents of one directory that may contain folders and/or other directori...
Definition: kmfolderdir.h:16
Mail folder.
Definition: kmfolder.h:69
TQString idString() const
Returns a string that can be used to identify this folder.
Definition: kmfolder.cpp:705
KMMsgInfo * unGetMsg(int idx)
Replace KMMessage with KMMsgInfo and delete KMMessage
Definition: kmfolder.cpp:326
KMMessage * getMsg(int idx)
Read message at given index.
Definition: kmfolder.cpp:321
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
static TQString localDataPath()
Returns the full path of the user's local data directory for KMail.
Definition: kmkernel.cpp:2111
This is a Mime Message.
Definition: kmmessage.h:68
TQString asPlainText(bool stripSignature, bool allowDecryption) const
Return the textual content of the message as plain text, converting HTML to plain text if necessary.
Definition: kmmessage.cpp:822
KMail message dictionary.
Definition: kmmsgdict.h:53
unsigned long getMsgSerNum(KMFolder *folder, int index) const
Find the message serial number for the message located at index index in folder folder.
Definition: kmmsgdict.cpp:345
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
This class is an abstraction of a search over messages.
Incoming mail is sent through the list of mail filter rules before it is placed in the associated mai...
TQCString field() const
Return message header field name (without the trailing ':').
Function function() const
Return filter function.
TQString contents() const
Return the value.