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
56namespace {
57const unsigned int MaintenanceLimit = 1000;
58const char* const folderIndexDisabledKey = "fulltextIndexDisabled";
59}
60
61#ifdef HAVE_INDEXLIB
62static
63TQValueList<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
69static
70std::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
80KMMsgIndex::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
138KMMsgIndex::~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
154bool 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
160bool 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
167void 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
193void 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
239void 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
265void KMMsgIndex::maintenance() {
266#ifdef HAVE_INDEXLIB
267 if ( mState != s_idle || tdeApp->hasPendingEvents() ) {
268 TQTimer::singleShot( 8000, this, TQ_SLOT( maintenance() ) );
269 return;
270 }
271 mIndex->maintenance();
272#endif
273}
274
275int 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
306void KMMsgIndex::act() {
307 kdDebug( 5006 ) << "KMMsgIndex::act()" << endl;
308 if ( tdeApp->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
355void 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
369void 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
400bool 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
435void KMMsgIndex::removeSearch( TQObject* destroyed ) {
436 mSearches.erase( std::find( mSearches.begin(), mSearches.end(), destroyed ) );
437}
438
439
440bool 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
452std::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
471bool 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
485void 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
496void 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
505void KMMsgIndex::scheduleAction() {
506#ifdef HAVE_INDEXLIB
507 if ( mState == s_willcreate || !mIndex ) return;
508 if ( !mSlowDown ) mTimer->start( 0 );
509#endif
510}
511
512void 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
525TQString KMMsgIndex::defaultPath() {
526 return KMKernel::localDataPath() + "text-index";
527}
528
529bool KMMsgIndex::creating() const {
530 return !mPendingMsgs.empty() || !mPendingFolders.empty();
531}
532
533KMMsgIndex::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
542KMMsgIndex::Search::~Search() {
543 delete mTimer;
544}
545
546void 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 ( tdeApp->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.