00001
00002
00003
00004
00005
00006
#include "kmfoldersearch.h"
00007
#include "kmfolderimap.h"
00008
#include "kmfoldermgr.h"
00009
#include "kmsearchpattern.h"
00010
#include "kmmsgdict.h"
00011
#include "kmmsgindex.h"
00012
#include "jobscheduler.h"
00013
00014
#include <kdebug.h>
00015
#include <klocale.h>
00016
#include <kconfig.h>
00017
00018
#include <qfileinfo.h>
00019
00020
#include <assert.h>
00021
#include <stdio.h>
00022
#include <unistd.h>
00023
#include <errno.h>
00024
#include <stdlib.h>
00025
#include <sys/types.h>
00026
#include <sys/stat.h>
00027
#include <sys/file.h>
00028
#include <utime.h>
00029
#include <config.h>
00030
00031
#ifdef HAVE_BYTESWAP_H
00032
#include <byteswap.h>
00033
#endif
00034
00035
00036
00037
00038
00039
#ifdef bswap_32
00040
#define kmail_swap_32(x) bswap_32(x)
00041
#else
00042
#define kmail_swap_32(x) \
00043
((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \
00044
(((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24))
00045
#endif
00046
00047
00048
#define IDS_VERSION 1000
00049
00050
#define IDS_HEADER "# KMail-Search-IDs V%d\n*"
00051
#define IDS_HEADER_LEN 30
00052
00053
00054 KMSearch::KMSearch(
QObject * parent,
const char * name)
00055 :
QObject(parent, name)
00056 {
00057 mRemainingFolders = -1;
00058 mRemainingMessages = -1;
00059 mRecursive =
true;
00060 mRunByIndex = mRunning =
false;
00061 mIdle =
false;
00062 mRoot = 0;
00063 mSearchPattern = 0;
00064 mSearchedCount = 0;
00065 mFoundCount = 0;
00066 mProcessNextBatchTimer =
new QTimer();
00067 connect(mProcessNextBatchTimer, SIGNAL(timeout()),
00068
this, SLOT(slotProcessNextBatch()));
00069 }
00070
00071 KMSearch::~KMSearch()
00072 {
00073
delete mProcessNextBatchTimer;
00074
delete mSearchPattern;
00075 }
00076
00077
bool KMSearch::write(
QString location)
const
00078
{
00079 KConfig config(location);
00080 config.setGroup(
"Search Folder");
00081
if (mSearchPattern)
00082 mSearchPattern->writeConfig(&config);
00083
if (mRoot.isNull())
00084 config.writeEntry(
"Base",
"");
00085
else
00086 config.writeEntry(
"Base", mRoot->idString());
00087 config.writeEntry(
"Recursive", recursive());
00088
return true;
00089 }
00090
00091
bool KMSearch::read(
QString location)
00092 {
00093 KConfig config(location);
00094 config.setGroup(
"Search Folder");
00095
if (!mSearchPattern)
00096 mSearchPattern =
new KMSearchPattern();
00097 mSearchPattern->readConfig(&config);
00098
QString rootString = config.readEntry(
"Base");
00099 mRoot = kmkernel->findFolderById(rootString);
00100 mRecursive = config.readBoolEntry(
"Recursive");
00101
return true;
00102 }
00103
00104
void KMSearch::setSearchPattern(
KMSearchPattern *searchPattern)
00105 {
00106
if (running())
00107 stop();
00108
if (mSearchPattern != searchPattern) {
00109
delete mSearchPattern;
00110 mSearchPattern = searchPattern;
00111 }
00112 }
00113
00114
bool KMSearch::inScope(
KMFolder* folder)
const
00115
{
00116
if (mRoot.isNull() || folder == mRoot)
00117
return true;
00118
if (!recursive())
00119
return false;
00120
00121
KMFolderDir *rootDir = mRoot->child();
00122
KMFolderDir *ancestorDir = folder->parent();
00123
while (ancestorDir) {
00124
if (ancestorDir == rootDir)
00125
return true;
00126 ancestorDir = ancestorDir->parent();
00127 }
00128
return false;
00129 }
00130
00131
void KMSearch::start()
00132 {
00133
if (running())
00134
return;
00135
00136
if (!mSearchPattern) {
00137 emit finished(
true);
00138
return;
00139 }
00140
00141 mSearchedCount = 0;
00142 mFoundCount = 0;
00143 mRunning =
true;
00144 mRunByIndex =
false;
00145
if(kmkernel->msgIndex() && kmkernel->msgIndex()->startQuery(
this)) {
00146 mRunByIndex =
true;
00147
return;
00148 }
00149
00150
QValueList<QGuardedPtr<KMFolder> > folders;
00151 folders.append(mRoot);
00152
if (recursive()) {
00153 KMFolderNode* node;
00154
KMFolder* folder;
00155
QValueListConstIterator<QGuardedPtr<KMFolder> > it;
00156
for (it = folders.begin(); it != folders.end(); ++it) {
00157 folder = *it;
00158
KMFolderDir *dir = 0;
00159
if (folder)
00160 dir = folder->
child();
00161
else
00162 dir = &kmkernel->folderMgr()->dir();
00163
if (!dir)
00164
continue;
00165
QPtrListIterator<KMFolderNode> it(*dir);
00166
while ((node = it.current())) {
00167 ++it;
00168
if (!node->isDir())
00169 {
00170
KMFolder* kmf = dynamic_cast<KMFolder*>(node);
00171
if (kmf)
00172 folders.append(kmf);
00173 }
00174 }
00175 }
00176 }
00177
00178 mLastFolder = QString::null;
00179 mRemainingFolders = folders.count();
00180 mRemainingMessages = 0;
00181
QValueListConstIterator<QGuardedPtr<KMFolder> > it;
00182
for (it = folders.begin(); it != folders.end(); ++it) {
00183
KMFolder *folder = *it;
00184
if (!folder) {
00185 --mRemainingFolders;
00186
continue;
00187 }
00188
00189
if (folder->
folderType() == KMFolderTypeImap) {
00190 KMFolderImap *imapFolder =
00191 dynamic_cast<KMFolderImap*>( folder->
storage() );
00192
if (imapFolder && imapFolder->getContentState() ==
00193 KMFolderImap::imapNoInformation) {
00194 mIncompleteFolders.append(imapFolder);
00195 connect(imapFolder, SIGNAL(folderComplete(KMFolderImap*,
bool)),
00196 SLOT(slotFolderComplete(KMFolderImap*,
bool)));
00197 imapFolder->getFolder();
00198 }
else {
00199 mFolders.append(folder);
00200 }
00201 }
else {
00202 mFolders.append(folder);
00203 }
00204 }
00205
00206 mProcessNextBatchTimer->start(0,
true);
00207 }
00208
00209
void KMSearch::stop()
00210 {
00211
if (!running())
00212
return;
00213
if(mRunByIndex) {
00214
if(kmkernel->msgIndex())
00215 kmkernel->msgIndex()->stopQuery(
this);
00216 }
else {
00217
00218
QValueListConstIterator<QGuardedPtr<KMFolderImap> > it;
00219
for (it = mIncompleteFolders.begin();
00220 it != mIncompleteFolders.end(); ++it) {
00221 KMFolderImap *aFolder = (*it);
00222
if (aFolder)
00223 disconnect(aFolder,
00224 SIGNAL(folderComplete(KMFolderImap*,
bool)),
00225
this,
00226 SLOT(slotFolderComplete(KMFolderImap*,
bool)));
00227 }
00228 mIncompleteFolders.clear();
00229
QValueListConstIterator<QGuardedPtr<KMFolder> > jt;
00230
for (jt = mOpenedFolders.begin(); jt != mOpenedFolders.end(); ++jt) {
00231
KMFolder *folder = *jt;
00232
if (folder)
00233 folder->
close();
00234 }
00235 }
00236 mOpenedFolders.clear();
00237 mRemainingMessages = -1;
00238 mRemainingFolders = -1;
00239 mFolders.clear();
00240 mLastFolder =
"";
00241 mRunByIndex = mRunning =
false;
00242 mIdle =
false;
00243 emit finished(
false);
00244 }
00245
00246
void KMSearch::slotProcessNextBatch()
00247 {
00248
if (!running())
00249
return;
00250 mIdle =
false;
00251
00252
if (mSerNums.count() != 0) {
00253
int i = 10;
00254
QValueListIterator<Q_UINT32> it;
00255
for (it = mSerNums.begin(); it != mSerNums.end();) {
00256
if (--i == 0)
00257
break;
00258
00259 Q_UINT32 serNum = *it;
00260 it = mSerNums.erase(it);
00261 --mRemainingMessages;
00262 ++mSearchedCount;
00263
00264
00265
00266
if (mSearchPattern && !mSearchPattern->matches(serNum))
00267
continue;
00268 emit found(serNum);
00269 ++mFoundCount;
00270 }
00271 mProcessNextBatchTimer->start(0,
true);
00272
return;
00273 }
00274
00275
if (mFolders.count() != 0) {
00276 --mRemainingFolders;
00277
KMFolder *folder = *(mFolders.begin());
00278
if (folder) {
00279
if (folder->
isSystemFolder())
00280 mLastFolder = i18n(folder->name().utf8());
00281
else
00282 mLastFolder = folder->name();
00283 }
00284 mFolders.erase(mFolders.begin());
00285
if (folder) {
00286 folder->
open();
00287 mOpenedFolders.append(folder);
00288
for(
int i = 0; i < folder->
count(); ++i) {
00289 Q_UINT32 serNum = kmkernel->msgDict()->getMsgSerNum(folder, i);
00290 ++mRemainingMessages;
00291
00292 mSerNums.prepend(serNum);
00293 }
00294 }
00295 mProcessNextBatchTimer->start(0,
true);
00296
return;
00297 }
00298
if (mRemainingFolders == 0) {
00299 mRunning =
false;
00300
QValueListConstIterator<QGuardedPtr<KMFolder> > it;
00301
for (it = mOpenedFolders.begin(); it != mOpenedFolders.end(); ++it) {
00302
KMFolder *folder = *it;
00303
if (folder)
00304 folder->
close();
00305 }
00306 mOpenedFolders.clear();
00307 mRemainingMessages = -1;
00308 mRemainingFolders = -1;
00309 mFolders.clear();
00310 mLastFolder =
"";
00311 emit finished(
true);
00312
return;
00313 }
00314
00315
00316 mIdle =
true;
00317 }
00318
00319
void KMSearch::slotFolderComplete(KMFolderImap *folder,
bool success)
00320 {
00321 disconnect(folder, SIGNAL(folderComplete(KMFolderImap*,
bool)),
00322
this, SLOT(slotFolderComplete(KMFolderImap*,
bool)));
00323
00324
if (success) {
00325
00326 mFolders.append(folder->folder());
00327
00328
00329
if (mIdle)
00330 mProcessNextBatchTimer->start(0,
true);
00331 }
else {
00332 stop();
00333 }
00334 }
00335
00336
00337
00338 KMFolderSearch::KMFolderSearch(
KMFolder* folder,
const char* name)
00339 :
FolderStorage(folder, name)
00340 {
00341 mIdsStream = 0;
00342 mSearch = 0;
00343 mInvalid =
false;
00344 mUnlinked =
true;
00345 mTempOpened =
false;
00346 setNoChildren(
true);
00347
00348
00349
00350 connect(kmkernel->folderMgr(), SIGNAL(msgAdded(
KMFolder*, Q_UINT32)),
00351
this, SLOT(examineAddedMessage(
KMFolder*, Q_UINT32)));
00352 connect(kmkernel->folderMgr(), SIGNAL(msgRemoved(
KMFolder*, Q_UINT32)),
00353
this, SLOT(examineRemovedMessage(
KMFolder*, Q_UINT32)));
00354 connect(kmkernel->folderMgr(), SIGNAL(msgChanged(
KMFolder*, Q_UINT32,
int)),
00355
this, SLOT(examineChangedMessage(
KMFolder*, Q_UINT32,
int)));
00356 connect(kmkernel->folderMgr(), SIGNAL(folderInvalidated(
KMFolder*)),
00357
this, SLOT(examineInvalidatedFolder(
KMFolder*)));
00358 connect(kmkernel->folderMgr(), SIGNAL(folderAdded(
KMFolder*)),
00359
this, SLOT(examineInvalidatedFolder(
KMFolder*)));
00360 connect(kmkernel->folderMgr(), SIGNAL(folderRemoved(
KMFolder*)),
00361
this, SLOT(examineRemovedFolder(
KMFolder*)));
00362 connect(kmkernel->folderMgr(), SIGNAL(msgHeaderChanged(
KMFolder*,
int)),
00363
this, SLOT(propagateHeaderChanged(
KMFolder*,
int)));
00364
00365 connect(kmkernel->imapFolderMgr(), SIGNAL(msgAdded(
KMFolder*, Q_UINT32)),
00366
this, SLOT(examineAddedMessage(
KMFolder*, Q_UINT32)));
00367 connect(kmkernel->imapFolderMgr(), SIGNAL(msgRemoved(
KMFolder*, Q_UINT32)),
00368
this, SLOT(examineRemovedMessage(
KMFolder*, Q_UINT32)));
00369 connect(kmkernel->imapFolderMgr(), SIGNAL(msgChanged(
KMFolder*, Q_UINT32,
int)),
00370
this, SLOT(examineChangedMessage(
KMFolder*, Q_UINT32,
int)));
00371 connect(kmkernel->imapFolderMgr(), SIGNAL(folderInvalidated(
KMFolder*)),
00372
this, SLOT(examineInvalidatedFolder(
KMFolder*)));
00373 connect(kmkernel->imapFolderMgr(), SIGNAL(folderAdded(
KMFolder*)),
00374
this, SLOT(examineInvalidatedFolder(
KMFolder*)));
00375 connect(kmkernel->imapFolderMgr(), SIGNAL(folderRemoved(
KMFolder*)),
00376
this, SLOT(examineRemovedFolder(
KMFolder*)));
00377 connect(kmkernel->imapFolderMgr(), SIGNAL(msgHeaderChanged(
KMFolder*,
int)),
00378
this, SLOT(propagateHeaderChanged(
KMFolder*,
int)));
00379
00380 connect(kmkernel->dimapFolderMgr(), SIGNAL(msgAdded(
KMFolder*, Q_UINT32)),
00381
this, SLOT(examineAddedMessage(
KMFolder*, Q_UINT32)));
00382 connect(kmkernel->dimapFolderMgr(), SIGNAL(msgRemoved(
KMFolder*, Q_UINT32)),
00383
this, SLOT(examineRemovedMessage(
KMFolder*, Q_UINT32)));
00384 connect(kmkernel->dimapFolderMgr(), SIGNAL(msgChanged(
KMFolder*, Q_UINT32,
int)),
00385
this, SLOT(examineChangedMessage(
KMFolder*, Q_UINT32,
int)));
00386 connect(kmkernel->dimapFolderMgr(), SIGNAL(folderInvalidated(
KMFolder*)),
00387
this, SLOT(examineInvalidatedFolder(
KMFolder*)));
00388 connect(kmkernel->dimapFolderMgr(), SIGNAL(folderAdded(
KMFolder*)),
00389
this, SLOT(examineInvalidatedFolder(
KMFolder*)));
00390 connect(kmkernel->dimapFolderMgr(), SIGNAL(folderRemoved(
KMFolder*)),
00391
this, SLOT(examineRemovedFolder(
KMFolder*)));
00392 connect(kmkernel->dimapFolderMgr(), SIGNAL(msgHeaderChanged(
KMFolder*,
int)),
00393
this, SLOT(propagateHeaderChanged(
KMFolder*,
int)));
00394
00395 mExecuteSearchTimer =
new QTimer();
00396 connect(mExecuteSearchTimer, SIGNAL(timeout()),
00397
this, SLOT(executeSearch()));
00398 }
00399
00400 KMFolderSearch::~KMFolderSearch()
00401 {
00402
delete mExecuteSearchTimer;
00403
delete mSearch;
00404 mSearch = 0;
00405
if (mOpenCount > 0)
00406 close(TRUE);
00407 }
00408
00409
void KMFolderSearch::setSearch(KMSearch *search)
00410 {
00411 truncateIndex();
00412 emit cleared();
00413 mInvalid =
false;
00414 setDirty(
true );
00415
if (!mUnlinked) {
00416 unlink(QFile::encodeName(indexLocation()));
00417 mUnlinked =
true;
00418 }
00419
if (mSearch != search) {
00420
delete mSearch;
00421 mSearch = search;
00422
if (mSearch) {
00423 QObject::connect(search, SIGNAL(found(Q_UINT32)),
00424 SLOT(addSerNum(Q_UINT32)));
00425 QObject::connect(search, SIGNAL(finished(
bool)),
00426 SLOT(searchFinished(
bool)));
00427 }
00428 }
00429
if (mSearch)
00430 mSearch->write(location());
00431 clearIndex();
00432 mTotalMsgs = 0;
00433 mUnreadMsgs = 0;
00434 emit numUnreadMsgsChanged( folder() );
00435 emit changed();
00436
00437
if (mSearch)
00438 mSearch->start();
00439 open();
00440 }
00441
00442
void KMFolderSearch::executeSearch()
00443 {
00444
if (mSearch)
00445 mSearch->stop();
00446 setSearch(mSearch);
00447
if ( folder()->parent() )
00448 folder()->parent()->manager()->invalidateFolder(kmkernel->msgDict(), folder() );
00449 }
00450
00451
const KMSearch* KMFolderSearch::search()
const
00452
{
00453
return mSearch;
00454 }
00455
00456
void KMFolderSearch::searchFinished(
bool success)
00457 {
00458
if (!success)
00459 mSerNums.clear();
00460 close();
00461 }
00462
00463
void KMFolderSearch::addSerNum(Q_UINT32 serNum)
00464 {
00465
if (mInvalid)
00466
return;
00467
int idx = -1;
00468
KMFolder *aFolder = 0;
00469 kmkernel->msgDict()->getLocation(serNum, &aFolder, &idx);
00470 assert(aFolder && (idx != -1));
00471
if(mFolders.findIndex(aFolder) == -1) {
00472 aFolder->
open();
00473
00474
if (mInvalid)
00475
return;
00476 mFolders.append(aFolder);
00477 }
00478 setDirty(
true );
00479
if (!mUnlinked) {
00480 unlink(QFile::encodeName(indexLocation()));
00481 mUnlinked =
true;
00482 }
00483 mSerNums.append(serNum);
00484 KMMsgBase *mb = aFolder->
getMsgBase(idx);
00485
if (mb->isUnread() || mb->isNew()) {
00486
if (mUnreadMsgs == -1)
00487 mUnreadMsgs = 0;
00488 ++mUnreadMsgs;
00489 emit numUnreadMsgsChanged( folder() );
00490 }
00491 emitMsgAddedSignals(mSerNums.count()-1);
00492 }
00493
00494
void KMFolderSearch::removeSerNum(Q_UINT32 serNum)
00495 {
00496
QValueVector<Q_UINT32>::const_iterator it;
00497
int i = 0;
00498
for(it = mSerNums.begin(); it != mSerNums.
end(); ++it, ++i)
00499
if ((*it) == serNum) {
00500
int idx = -1;
00501
KMFolder *aFolder = 0;
00502 kmkernel->msgDict()->getLocation(serNum, &aFolder, &idx);
00503 assert(aFolder && (idx != -1));
00504 emit msgRemoved(folder(), serNum);
00505 removeMsg(i);
00506
return;
00507 }
00508
if (!mUnlinked) {
00509 unlink(QFile::encodeName(indexLocation()));
00510 mUnlinked =
true;
00511 }
00512 }
00513
00514
QCString& KMFolderSearch::getMsgString(
int idx,
QCString& mDest)
00515 {
00516
KMFolder *folder = getMsgBase(idx)->parent();
00517 assert(folder);
00518
return folder->
getMsgString(folder->
find(getMsgBase(idx)), mDest);
00519 }
00520
00521
int KMFolderSearch::addMsg(KMMessage*,
int* index_return)
00522 {
00523
00524 *index_return = -1;
00525
return 0;
00526 }
00527
00528
bool KMFolderSearch::readSearch()
00529 {
00530 mSearch =
new KMSearch;
00531 QObject::connect(mSearch, SIGNAL(found(Q_UINT32)), SLOT(addSerNum(Q_UINT32)));
00532 QObject::connect(mSearch, SIGNAL(finished(
bool)), SLOT(searchFinished(
bool)));
00533
return mSearch->read(location());
00534 }
00535
00536
int KMFolderSearch::open()
00537 {
00538 mOpenCount++;
00539 kmkernel->jobScheduler()->notifyOpeningFolder( folder() );
00540
if (mOpenCount > 1)
00541
return 0;
00542
00543 readConfig();
00544
if (!mSearch && !readSearch())
00545
return -1;
00546
00547 emit cleared();
00548
if (!mSearch || !search()->running())
00549
if (!readIndex()) {
00550 executeSearch();
00551 }
00552
00553
return 0;
00554 }
00555
00556
int KMFolderSearch::canAccess()
00557 {
00558 assert(!folder()->name().isEmpty());
00559
00560
if (access(QFile::encodeName(location()), R_OK | W_OK | X_OK) != 0)
00561
return 1;
00562
return 0;
00563 }
00564
00565
void KMFolderSearch::sync()
00566 {
00567
if (mDirty) {
00568
if (mSearch)
00569 mSearch->write(location());
00570 updateIndex();
00571 }
00572 }
00573
00574
void KMFolderSearch::close(
bool force)
00575 {
00576
if (mOpenCount <= 0)
return;
00577
if (mOpenCount > 0) mOpenCount--;
00578
if (mOpenCount > 0 && !force)
return;
00579
00580
if (mAutoCreateIndex) {
00581
if (mSearch)
00582 mSearch->write(location());
00583 updateIndex();
00584
if (mSearch && search()->running())
00585 mSearch->stop();
00586 writeConfig();
00587 }
00588
00589
00590
QValueListIterator<QGuardedPtr<KMFolder> > fit;
00591
for (fit = mFolders.begin(); fit != mFolders.end(); ++fit) {
00592
if (!(*fit))
00593
continue;
00594 (*fit)->close();
00595 }
00596 mFolders.clear();
00597
00598 clearIndex(TRUE);
00599
00600
if (mIdsStream)
00601 fclose(mIdsStream);
00602
00603 mOpenCount = 0;
00604 mIdsStream = 0;
00605 mUnreadMsgs = -1;
00606 }
00607
00608
int KMFolderSearch::create(
bool)
00609 {
00610
int old_umask;
00611
int rc = unlink(QFile::encodeName(location()));
00612
if (!rc)
00613
return rc;
00614 rc = 0;
00615
00616 assert(!folder()->name().isEmpty());
00617 assert(mOpenCount == 0);
00618
00619 kdDebug(5006) <<
"Creating folder " << location() << endl;
00620
if (access(QFile::encodeName(location()), F_OK) == 0) {
00621 kdDebug(5006) <<
"KMFolderSearch::create call to access function failed."
00622 << endl;
00623
return EEXIST;
00624 }
00625
00626 old_umask = umask(077);
00627 FILE *mStream = fopen(QFile::encodeName(location()),
"w+");
00628 umask(old_umask);
00629
if (!mStream)
return errno;
00630 fclose(mStream);
00631
00632 clearIndex();
00633
if (!mSearch) {
00634 mSearch =
new KMSearch();
00635 QObject::connect(mSearch, SIGNAL(found(Q_UINT32)), SLOT(addSerNum(Q_UINT32)));
00636 QObject::connect(mSearch, SIGNAL(finished(
bool)), SLOT(searchFinished(
bool)));
00637 }
00638 mSearch->write(location());
00639 mOpenCount++;
00640 mChanged =
false;
00641 mUnreadMsgs = 0;
00642 mTotalMsgs = 0;
00643
return rc;
00644 }
00645
00646
int KMFolderSearch::compact(
bool )
00647 {
00648 needsCompact =
false;
00649
return 0;
00650 }
00651
00652
bool KMFolderSearch::isReadOnly()
const
00653
{
00654
return false;
00655 }
00656
00657 FolderJob* KMFolderSearch::doCreateJob(KMMessage*, FolderJob::JobType,
00658
KMFolder*,
QString,
const AttachmentStrategy* )
const
00659
{
00660
00661 assert(0);
00662
return 0;
00663 }
00664
00665 FolderJob* KMFolderSearch::doCreateJob(
QPtrList<KMMessage>&,
const QString&,
00666 FolderJob::JobType,
KMFolder*)
const
00667
{
00668
00669 assert(0);
00670
return 0;
00671 }
00672
00673
const KMMsgBase* KMFolderSearch::getMsgBase(
int idx)
const
00674
{
00675
int folderIdx = -1;
00676
KMFolder *folder = 0;
00677
if (idx < 0 || (Q_UINT32)idx >= mSerNums.count())
00678
return 0;
00679 kmkernel->msgDict()->getLocation(mSerNums[idx], &folder, &folderIdx);
00680 assert(folder && (folderIdx != -1));
00681
return folder->
getMsgBase(folderIdx);
00682 }
00683
00684 KMMsgBase* KMFolderSearch::getMsgBase(
int idx)
00685 {
00686
int folderIdx = -1;
00687
KMFolder *folder = 0;
00688
if (idx < 0 || (Q_UINT32)idx >= mSerNums.count())
00689
return 0;
00690 kmkernel->msgDict()->getLocation(mSerNums[idx], &folder, &folderIdx);
00691
if (!folder || folderIdx == -1)
00692
return 0;
00693
return folder->
getMsgBase(folderIdx);
00694 }
00695
00696
00697 KMMessage* KMFolderSearch::getMsg(
int idx)
00698 {
00699
int folderIdx = -1;
00700
KMFolder *folder = 0;
00701
if (idx < 0 || (Q_UINT32)idx >= mSerNums.count())
00702
return 0;
00703 kmkernel->msgDict()->getLocation(mSerNums[idx], &folder, &folderIdx);
00704 assert(folder && (folderIdx != -1));
00705 KMMessage* msg = folder->
getMsg( folderIdx );
00706
return msg;
00707 }
00708
00709
00710
void
00711 KMFolderSearch::ignoreJobsForMessage( KMMessage* msg )
00712 {
00713
if ( !msg || msg->transferInProgress() )
00714
return;
00715
00716
00717
00718
FolderStorage::ignoreJobsForMessage( msg );
00719
00720
if (msg->parent()->folderType() == KMFolderTypeImap) {
00721 KMAcctImap *account =
00722 static_cast<KMFolderImap*>( msg->storage() )->account();
00723
if( !account )
00724
return;
00725 account->ignoreJobsForMessage( msg );
00726 }
00727 }
00728
00729
00730
int KMFolderSearch::find(
const KMMsgBase* msg)
const
00731
{
00732
int pos = 0;
00733 Q_UINT32 serNum = msg->getMsgSerNum();
00734
QValueVector<Q_UINT32>::const_iterator it;
00735
for(it = mSerNums.begin(); it != mSerNums.
end(); ++it) {
00736
if ((*it) == serNum)
00737
return pos;
00738 ++pos;
00739 }
00740
return -1;
00741 }
00742
00743
QString KMFolderSearch::indexLocation()
const
00744
{
00745
QString sLocation(folder()->
path());
00746
00747
if (!sLocation.isEmpty()) sLocation +=
'/';
00748 sLocation +=
'.';
00749 sLocation += dotEscape(fileName());
00750 sLocation +=
".index";
00751 sLocation +=
".search";
00752
00753
return sLocation;
00754 }
00755
00756
int KMFolderSearch::updateIndex()
00757 {
00758
if (mSearch && search()->running())
00759 unlink(QFile::encodeName(indexLocation()));
00760
else
00761
if (dirty())
00762
return writeIndex();
00763
return 0;
00764 }
00765
00766
int KMFolderSearch::writeIndex(
bool )
00767 {
00768
00769
00770
QString filename = indexLocation();
00771
int old_umask = umask(077);
00772
QString tempName = filename +
".temp";
00773 unlink(QFile::encodeName(tempName));
00774
00775
00776
00777 utime(QFile::encodeName(location()), 0);
00778
00779 FILE *tmpIndexStream = fopen(QFile::encodeName(tempName),
"w");
00780 umask(old_umask);
00781
00782
if (!tmpIndexStream) {
00783 kdDebug(5006) <<
"Cannot write '" << filename
00784 << strerror(errno) <<
" (" << errno <<
")" << endl;
00785 truncate(QFile::encodeName(filename), 0);
00786
return -1;
00787 }
00788 fprintf(tmpIndexStream, IDS_HEADER, IDS_VERSION);
00789 Q_UINT32 byteOrder = 0x12345678;
00790 fwrite(&byteOrder,
sizeof(byteOrder), 1, tmpIndexStream);
00791
00792 Q_UINT32 count = mSerNums.count();
00793
if (!fwrite(&count,
sizeof(count), 1, tmpIndexStream)) {
00794 fclose(tmpIndexStream);
00795 truncate(QFile::encodeName(filename), 0);
00796
return -1;
00797 }
00798
00799
QValueVector<Q_UINT32>::iterator it;
00800
for(it = mSerNums.begin(); it != mSerNums.
end(); ++it) {
00801 Q_UINT32 serNum = *it;
00802
if (!fwrite(&serNum,
sizeof(serNum), 1, tmpIndexStream))
00803
return -1;
00804 }
00805
if (ferror(tmpIndexStream))
return ferror(tmpIndexStream);
00806
if (fflush(tmpIndexStream) != 0)
return errno;
00807
if (fsync(fileno(tmpIndexStream)) != 0)
return errno;
00808
if (fclose(tmpIndexStream) != 0)
return errno;
00809
00810 ::rename(QFile::encodeName(tempName), QFile::encodeName(indexLocation()));
00811 mDirty = FALSE;
00812 mUnlinked = FALSE;
00813
00814
return 0;
00815 }
00816
00817 DwString KMFolderSearch::getDwString(
int idx)
00818 {
00819
return getMsgBase(idx)->parent()->
getDwString( idx );
00820 }
00821
00822 KMMessage* KMFolderSearch::readMsg(
int idx)
00823 {
00824
int folderIdx = -1;
00825
KMFolder *folder = 0;
00826 kmkernel->msgDict()->getLocation(mSerNums[idx], &folder, &folderIdx);
00827 assert(folder && (folderIdx != -1));
00828
return folder->
getMsg( folderIdx );
00829 }
00830
00831
bool KMFolderSearch::readIndex()
00832 {
00833 clearIndex();
00834
QString filename = indexLocation();
00835 mIdsStream = fopen(QFile::encodeName(filename),
"r+");
00836
if (!mIdsStream)
00837
return false;
00838
00839
int version = 0;
00840 fscanf(mIdsStream, IDS_HEADER, &version);
00841
if (version != IDS_VERSION) {
00842 fclose(mIdsStream);
00843 mIdsStream = 0;
00844
return false;
00845 }
00846
bool swapByteOrder;
00847 Q_UINT32 byte_order;
00848
if (!fread(&byte_order,
sizeof(byte_order), 1, mIdsStream)) {
00849 fclose(mIdsStream);
00850 mIdsStream = 0;
00851
return false;
00852 }
00853 swapByteOrder = (byte_order == 0x78563412);
00854
00855 Q_UINT32 count;
00856
if (!fread(&count,
sizeof(count), 1, mIdsStream)) {
00857 fclose(mIdsStream);
00858 mIdsStream = 0;
00859
return false;
00860 }
00861
if (swapByteOrder)
00862 count = kmail_swap_32(count);
00863
00864 mUnreadMsgs = 0;
00865 mSerNums.reserve(count);
00866
for (
unsigned int index = 0; index < count; index++) {
00867 Q_UINT32 serNum;
00868
int folderIdx = -1;
00869
KMFolder *folder = 0;
00870
bool readOk = fread(&serNum,
sizeof(serNum), 1, mIdsStream);
00871
if (!readOk) {
00872 clearIndex();
00873 fclose(mIdsStream);
00874 mIdsStream = 0;
00875
return false;
00876 }
00877
if (swapByteOrder)
00878 serNum = kmail_swap_32(serNum);
00879
00880 kmkernel->msgDict()->getLocation( serNum, &folder, &folderIdx );
00881
if (!folder || (folderIdx == -1)) {
00882 clearIndex();
00883 fclose(mIdsStream);
00884 mIdsStream = 0;
00885
return false;
00886 }
00887 mSerNums.push_back(serNum);
00888
if(mFolders.findIndex(folder) == -1) {
00889 folder->
open();
00890
if (mInvalid)
00891
return false;
00892 mFolders.append(folder);
00893 }
00894 KMMsgBase *mb = folder->
getMsgBase(folderIdx);
00895
if (!mb)
00896
return false;
00897
if (mb->isNew() || mb->isUnread()) {
00898
if (mUnreadMsgs == -1) ++mUnreadMsgs;
00899 ++mUnreadMsgs;
00900 }
00901 }
00902 mTotalMsgs = mSerNums.count();
00903 fclose(mIdsStream);
00904 mIdsStream = 0;
00905 mUnlinked =
true;
00906
return true;
00907 }
00908
00909
int KMFolderSearch::removeContents()
00910 {
00911 unlink(QFile::encodeName(location()));
00912 unlink(QFile::encodeName(indexLocation()));
00913 mUnlinked =
true;
00914
return 0;
00915 }
00916
00917
int KMFolderSearch::expungeContents()
00918 {
00919 setSearch(
new KMSearch());
00920
return 0;
00921 }
00922
00923
int KMFolderSearch::count(
bool cache)
const
00924
{
00925 Q_UNUSED(cache);
00926
return mSerNums.count();
00927 }
00928
00929 KMMsgBase* KMFolderSearch::takeIndexEntry(
int idx)
00930 {
00931 assert(idx >= 0 && idx < (
int)mSerNums.count());
00932 KMMsgBase *msgBase = getMsgBase(idx);
00933
QValueVector<Q_UINT32>::iterator it = mSerNums.begin();
00934 mSerNums.erase(&it[idx]);
00935
return msgBase;
00936 }
00937
00938 KMMsgInfo* KMFolderSearch::setIndexEntry(
int idx, KMMessage *msg)
00939 {
00940 assert(idx >= 0 && idx < (
int)mSerNums.count());
00941 Q_UNUSED( idx );
00942
return msg->storage()->setIndexEntry(msg->parent()->find(msg), msg);
00943 }
00944
00945
void KMFolderSearch::clearIndex(
bool,
bool)
00946 {
00947 mSerNums.clear();
00948 }
00949
00950
void KMFolderSearch::fillDictFromIndex(KMMsgDict *)
00951 {
00952
00953
return;
00954 }
00955
00956
void KMFolderSearch::truncateIndex()
00957 {
00958 truncate(QFile::encodeName(indexLocation()), IDS_HEADER_LEN);
00959 }
00960
00961
void KMFolderSearch::examineAddedMessage(
KMFolder *aFolder, Q_UINT32 serNum)
00962 {
00963
if (!search() && !readSearch())
00964
return;
00965
if (!search()->inScope(aFolder))
00966
return;
00967
if (!mTempOpened) {
00968 open();
00969 mTempOpened =
true;
00970 }
00971
00972
if (!search()->searchPattern())
00973
return;
00974
00975
int idx = -1;
00976
KMFolder *folder = 0;
00977 kmkernel->msgDict()->getLocation(serNum, &folder, &idx);
00978 assert(folder && (idx != -1));
00979 assert(folder == aFolder);
00980
if (!folder->
isOpened())
00981
return;
00982
00983
if (folder->
folderType() == KMFolderTypeImap) {
00984
00985
00986 KMFolderImap *imapFolder =
00987 dynamic_cast<KMFolderImap*> ( folder->
storage() );
00988
if (!mSearch->running()) {
00989 mUnexaminedMessages.push(serNum);
00990 disconnect(imapFolder, SIGNAL(folderComplete(KMFolderImap*,
bool)),
00991
this, SLOT (examineCompletedFolder(KMFolderImap*,
bool)));
00992 connect(imapFolder, SIGNAL(folderComplete(KMFolderImap*,
bool)),
00993
this, SLOT (examineCompletedFolder(KMFolderImap*,
bool)));
00994 }
00995 }
else {
00996
if (search()->searchPattern()->matches(serNum))
00997
if (mSearch->running()) {
00998 mSearch->stop();
00999 mExecuteSearchTimer->start(0,
true);
01000 }
else {
01001 addSerNum(serNum);
01002 }
01003 }
01004 }
01005
01006
void KMFolderSearch::examineCompletedFolder(KMFolderImap *aFolder,
bool success)
01007 {
01008 disconnect (aFolder, SIGNAL(folderComplete(KMFolderImap*,
bool)),
01009
this, SLOT(examineCompletedFolder(KMFolderImap*,
bool)));
01010
if (!success)
return;
01011 Q_UINT32 serNum;
01012
while (!mUnexaminedMessages.isEmpty()) {
01013 serNum = mUnexaminedMessages.pop();
01014
if (search()->searchPattern()->matches(serNum))
01015 addSerNum(serNum);
01016 }
01017 }
01018
01019
void KMFolderSearch::examineRemovedMessage(
KMFolder *folder, Q_UINT32 serNum)
01020 {
01021
if (!search() && !readSearch())
01022
return;
01023
if (!search()->inScope(folder))
01024
return;
01025
if (!mTempOpened) {
01026 open();
01027 mTempOpened =
true;
01028 }
01029
01030
if (mSearch->running()) {
01031 mSearch->stop();
01032 mExecuteSearchTimer->start(0,
true);
01033 }
else {
01034 removeSerNum(serNum);
01035 }
01036 }
01037
01038
void KMFolderSearch::examineChangedMessage(
KMFolder *aFolder, Q_UINT32 serNum,
int delta)
01039 {
01040
if (!search() && !readSearch())
01041
return;
01042
if (!search()->inScope(aFolder))
01043
return;
01044
if (!mTempOpened) {
01045 open();
01046 mTempOpened =
true;
01047 }
01048
QValueVector<Q_UINT32>::const_iterator it;
01049 it = qFind( mSerNums.begin(), mSerNums.end(), serNum );
01050
if (it != mSerNums.
end()) {
01051 mUnreadMsgs += delta;
01052 emit numUnreadMsgsChanged( folder() );
01053 emit msgChanged( folder(), serNum, delta );
01054 }
01055 }
01056
01057
void KMFolderSearch::examineInvalidatedFolder(
KMFolder *folder)
01058 {
01059
if (!search() && !readSearch())
01060
return;
01061
if (!search()->inScope(folder))
01062
return;
01063
if (mTempOpened) {
01064 close();
01065 mTempOpened =
false;
01066 }
01067
01068 mInvalid =
true;
01069
if (mSearch)
01070 mSearch->stop();
01071
01072
if (!mUnlinked) {
01073 unlink(QFile::encodeName(indexLocation()));
01074 mUnlinked =
true;
01075 }
01076
01077
if (!isOpened())
01078
return;
01079
01080
if (!mTempOpened) {
01081 open();
01082 mTempOpened =
true;
01083 }
01084 mExecuteSearchTimer->start(0,
true);
01085 }
01086
01087
void KMFolderSearch::examineRemovedFolder(
KMFolder *folder)
01088 {
01089 examineInvalidatedFolder(folder);
01090
if (mSearch->root() == folder) {
01091
delete mSearch;
01092 mSearch = 0;
01093 }
01094 }
01095
01096
void KMFolderSearch::propagateHeaderChanged(
KMFolder *aFolder,
int idx)
01097 {
01098
int pos = 0;
01099
if (!search() && !readSearch())
01100
return;
01101
if (!search()->inScope(aFolder))
01102
return;
01103
if (!mTempOpened) {
01104 open();
01105 mTempOpened =
true;
01106 }
01107
01108 Q_UINT32 serNum = kmkernel->msgDict()->getMsgSerNum(aFolder, idx);
01109
QValueVector<Q_UINT32>::const_iterator it;
01110
for(it = mSerNums.begin(); it != mSerNums.
end(); ++it) {
01111
if ((*it) == serNum) {
01112 emit msgHeaderChanged(folder(), pos);
01113
return;
01114 }
01115 ++pos;
01116 }
01117 }
01118
01119
void KMFolderSearch::tryReleasingFolder(
KMFolder* folder)
01120 {
01121
01122
01123
if ( mTempOpened && mOpenCount == 1 )
01124 {
01125 examineInvalidatedFolder( folder );
01126 }
01127 }
01128
01129
#include "kmfoldersearch.moc"