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