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 
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
KMMessage * getMsg(int idx)
Read message at given index.
Definition: kmfolder.cpp:321
static const KMMsgDict * instance()
Access the globally unique MessageDict.
Definition: kmmsgdict.cpp:167
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 list that manages the contents of one directory that may contain folders and/or other directori...
Definition: kmfolderdir.h:15
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 ':').
TQString contents() const
Return the value.
int open(const char *owner)
Open folder for access.
Definition: kmfolder.cpp:479
int count(bool cache=false) const
Number of messages in this folder.
Definition: kmfolder.cpp:445
KMMsgInfo * unGetMsg(int idx)
Replace KMMessage with KMMsgInfo and delete KMMessage
Definition: kmfolder.cpp:326
TQString idString() const
Returns a string that can be used to identify this folder.
Definition: kmfolder.cpp:705
Function function() const
Return filter function.
This is a Mime Message.
Definition: kmmessage.h:67
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
static TQString localDataPath()
Returns the full path of the user's local data directory for KMail.
Definition: kmkernel.cpp:2111
KMail message dictionary.
Definition: kmmsgdict.h:52
This class is an abstraction of a search over messages.
Mail folder.
Definition: kmfolder.h:68