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"