00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #include <config.h>
00036
00037 #include "folderstorage.h"
00038 #include "kmfolder.h"
00039 #include "kmkernel.h"
00040
00041 #include "kmfolderimap.h"
00042 #include "undostack.h"
00043 #include "kmmsgdict.h"
00044 #include "kmfoldermgr.h"
00045 #include "kmcommands.h"
00046 #include "listjob.h"
00047 using KMail::ListJob;
00048 #include "kmsearchpattern.h"
00049 #include "globalsettings.h"
00050
00051 #include <klocale.h>
00052 #include <kconfig.h>
00053 #include <kdebug.h>
00054
00055 #include <qfile.h>
00056 #include <qregexp.h>
00057
00058 #include <mimelib/mimepp.h>
00059 #include <errno.h>
00060
00061
00062
00063 FolderStorage::FolderStorage( KMFolder* folder, const char* aName )
00064 : QObject( folder, aName ), mFolder( folder ), mEmitChangedTimer( 0L )
00065 {
00066 mOpenCount = 0;
00067 mQuiet = 0;
00068 mChanged = false;
00069 mAutoCreateIndex = true;
00070 mExportsSernums = false;
00071 mDirty = false;
00072 mUnreadMsgs = -1;
00073 mGuessedUnreadMsgs = -1;
00074 mTotalMsgs = -1;
00075 mSize = -1;
00076 needsCompact = false;
00077 mConvertToUtf8 = false;
00078 mCompactable = true;
00079 mNoContent = false;
00080 mNoChildren = false;
00081 mRDict = 0;
00082 mDirtyTimer = new QTimer(this, "mDirtyTimer");
00083 connect(mDirtyTimer, SIGNAL(timeout()),
00084 this, SLOT(updateIndex()));
00085
00086 mHasChildren = HasNoChildren;
00087 mContentsType = KMail::ContentsTypeMail;
00088
00089 connect(this, SIGNAL(closed(KMFolder*)), mFolder, SIGNAL(closed()));
00090 }
00091
00092
00093 FolderStorage::~FolderStorage()
00094 {
00095 mJobList.setAutoDelete( true );
00096 QObject::disconnect( SIGNAL(destroyed(QObject*)), this, 0 );
00097 mJobList.clear();
00098 KMMsgDict::deleteRentry(mRDict);
00099 }
00100
00101
00102 void FolderStorage::close( const char* owner, bool aForced )
00103 {
00104 if (mOpenCount <= 0) return;
00105 if (mOpenCount > 0) mOpenCount--;
00106 if (mOpenCount > 0 && !aForced) return;
00107
00108
00109 reallyDoClose(owner);
00110 }
00111
00112
00113 QString FolderStorage::dotEscape(const QString& aStr)
00114 {
00115 if (aStr[0] != '.') return aStr;
00116 return aStr.left(aStr.find(QRegExp("[^\\.]"))) + aStr;
00117 }
00118
00119 void FolderStorage::addJob( FolderJob* job ) const
00120 {
00121 QObject::connect( job, SIGNAL(destroyed(QObject*)),
00122 SLOT(removeJob(QObject*)) );
00123 mJobList.append( job );
00124 }
00125
00126 void FolderStorage::removeJob( QObject* job )
00127 {
00128 mJobList.remove( static_cast<FolderJob*>( job ) );
00129 }
00130
00131
00132
00133 QString FolderStorage::location() const
00134 {
00135 QString sLocation(const_cast<FolderStorage*>(this)->folder()->path());
00136
00137 if (!sLocation.isEmpty()) sLocation += '/';
00138 sLocation += dotEscape(fileName());
00139
00140 return sLocation;
00141 }
00142
00143 QString FolderStorage::fileName() const
00144 {
00145 return mFolder->name();
00146 }
00147
00148
00149
00150
00151 void FolderStorage::setAutoCreateIndex(bool autoIndex)
00152 {
00153 mAutoCreateIndex = autoIndex;
00154 }
00155
00156
00157 void FolderStorage::setDirty(bool f)
00158 {
00159 mDirty = f;
00160 if (mDirty && mAutoCreateIndex)
00161 mDirtyTimer->changeInterval( mDirtyTimerInterval );
00162 else
00163 mDirtyTimer->stop();
00164 }
00165
00166
00167 void FolderStorage::markNewAsUnread()
00168 {
00169 KMMsgBase* msgBase;
00170 int i;
00171
00172 for (i=0; i< count(); ++i)
00173 {
00174 if (!(msgBase = getMsgBase(i))) continue;
00175 if (msgBase->isNew())
00176 {
00177 msgBase->setStatus(KMMsgStatusUnread);
00178 msgBase->setDirty(true);
00179 }
00180 }
00181 }
00182
00183 void FolderStorage::markUnreadAsRead()
00184 {
00185 KMMsgBase* msgBase;
00186 SerNumList serNums;
00187
00188 for (int i=count()-1; i>=0; --i)
00189 {
00190 msgBase = getMsgBase(i);
00191 assert(msgBase);
00192 if (msgBase->isNew() || msgBase->isUnread())
00193 {
00194 serNums.append( msgBase->getMsgSerNum() );
00195 }
00196 }
00197 if (serNums.empty())
00198 return;
00199
00200 KMCommand *command = new KMSetStatusCommand( KMMsgStatusRead, serNums );
00201 command->start();
00202 }
00203
00204
00205 void FolderStorage::quiet(bool beQuiet)
00206 {
00207
00208 if (beQuiet)
00209 {
00210
00211
00212
00213 if ( !mEmitChangedTimer) {
00214 mEmitChangedTimer= new QTimer( this, "mEmitChangedTimer" );
00215 connect( mEmitChangedTimer, SIGNAL( timeout() ),
00216 this, SLOT( slotEmitChangedTimer() ) );
00217 }
00218 mQuiet++;
00219 } else {
00220 mQuiet--;
00221 if (mQuiet <= 0)
00222 {
00223 delete mEmitChangedTimer;
00224 mEmitChangedTimer=0L;
00225
00226 mQuiet = 0;
00227 if (mChanged) {
00228 emit changed();
00229
00230
00231 emit numUnreadMsgsChanged( folder() );
00232 }
00233 mChanged = false;
00234 }
00235 }
00236 }
00237
00238
00239
00241 int operator<( KMMsgBase & m1, KMMsgBase & m2 )
00242 {
00243 return (m1.date() < m2.date());
00244 }
00245
00247 int operator==( KMMsgBase & m1, KMMsgBase & m2 )
00248 {
00249 return (m1.date() == m2.date());
00250 }
00251
00252
00253
00254 int FolderStorage::expungeOldMsg(int days)
00255 {
00256 int i, msgnb=0;
00257 time_t msgTime, maxTime;
00258 const KMMsgBase* mb;
00259 QValueList<int> rmvMsgList;
00260
00261 maxTime = time(0) - days * 3600 * 24;
00262
00263 for (i=count()-1; i>=0; i--) {
00264 mb = getMsgBase(i);
00265 assert(mb);
00266 msgTime = mb->date();
00267
00268 if (msgTime < maxTime) {
00269
00270 removeMsg( i );
00271 msgnb++;
00272 }
00273 }
00274 return msgnb;
00275 }
00276
00277
00278 void FolderStorage::slotEmitChangedTimer()
00279 {
00280 emit changed();
00281 mChanged=false;
00282 }
00283
00284 void FolderStorage::emitMsgAddedSignals(int idx)
00285 {
00286 Q_UINT32 serNum = KMMsgDict::instance()->getMsgSerNum( folder() , idx );
00287 if (!mQuiet) {
00288 emit msgAdded(idx);
00289 } else {
00292 if ( !mEmitChangedTimer->isActive() ) {
00293 mEmitChangedTimer->start( 3000 );
00294 }
00295 mChanged=true;
00296 }
00297 emit msgAdded( folder(), serNum );
00298 }
00299
00300
00301 bool FolderStorage::canAddMsgNow(KMMessage* aMsg, int* aIndex_ret)
00302 {
00303 if (aIndex_ret) *aIndex_ret = -1;
00304 KMFolder *msgParent = aMsg->parent();
00305
00306
00307 if (aMsg->transferInProgress() && msgParent)
00308 return false;
00309 if (!aMsg->isComplete() && msgParent && msgParent->folderType() == KMFolderTypeImap)
00310 {
00311 FolderJob *job = msgParent->createJob(aMsg);
00312 connect(job, SIGNAL(messageRetrieved(KMMessage*)),
00313 SLOT(reallyAddMsg(KMMessage*)));
00314 job->start();
00315 aMsg->setTransferInProgress( true );
00316 return false;
00317 }
00318 return true;
00319 }
00320
00321
00322
00323 void FolderStorage::reallyAddMsg(KMMessage* aMsg)
00324 {
00325 if (!aMsg)
00326 return;
00327 aMsg->setTransferInProgress( false );
00328 aMsg->setComplete( true );
00329 KMFolder *aFolder = aMsg->parent();
00330 int index;
00331 ulong serNum = aMsg->getMsgSerNum();
00332 bool undo = aMsg->enableUndo();
00333 addMsg(aMsg, &index);
00334 if (index < 0) return;
00335 unGetMsg(index);
00336 if (undo)
00337 {
00338 kmkernel->undoStack()->pushSingleAction( serNum, aFolder, folder() );
00339 }
00340 }
00341
00342
00343
00344 void FolderStorage::reallyAddCopyOfMsg(KMMessage* aMsg)
00345 {
00346 if ( !aMsg ) return;
00347 aMsg->setParent( 0 );
00348 aMsg->setTransferInProgress( false );
00349 addMsg( aMsg );
00350 unGetMsg( count() - 1 );
00351 }
00352
00353 int FolderStorage::find( const KMMessage * msg ) const {
00354 return find( &msg->toMsgBase() );
00355 }
00356
00357
00358 void FolderStorage::removeMsg(const QPtrList<KMMsgBase>& msgList, bool imapQuiet)
00359 {
00360
00361 emit batchRemovingStarted();
00362 int i = 0;
00363 for( QPtrListIterator<KMMsgBase> it( msgList ); *it; ++it )
00364 {
00365 if ( i == msgList.count() - 1 ) {
00366
00367
00368 emit batchRemovingFinished();
00369 }
00370
00371 int idx = find(it.current());
00372
00373 if ( idx == -1 ) {
00374 kdWarning(5006) << "Going to crash. Subject of faulty message is "
00375 << it.current()->subject()
00376 << "; filename = " << it.current()->fileName()
00377 << endl;
00378 assert( false && " idx != 1 " );
00379 }
00380
00381 removeMsg(idx, imapQuiet);
00382 ++i;
00383 }
00384 }
00385
00386
00387 void FolderStorage::removeMsg(const QPtrList<KMMessage>& msgList, bool imapQuiet)
00388 {
00389 for( QPtrListIterator<KMMessage> it( msgList ); *it; ++it )
00390 {
00391 int idx = find(it.current());
00392 assert( idx != -1);
00393 removeMsg(idx, imapQuiet);
00394 }
00395 }
00396
00397
00398 void FolderStorage::removeMsg(int idx, bool)
00399 {
00400
00401
00402 if(idx < 0)
00403 {
00404 kdDebug(5006) << "FolderStorage::removeMsg() : idx < 0\n" << endl;
00405 return;
00406 }
00407
00408 KMMsgBase* mb = getMsgBase(idx);
00409
00410 Q_UINT32 serNum = KMMsgDict::instance()->getMsgSerNum( folder(), idx );
00411 if (serNum != 0)
00412 emit msgRemoved( folder(), serNum );
00413 mb = takeIndexEntry( idx );
00414
00415 setDirty( true );
00416 needsCompact=true;
00417
00418 if (mb->isUnread() || mb->isNew() ||
00419 (folder() == kmkernel->outboxFolder())) {
00420 --mUnreadMsgs;
00421 if ( !mQuiet ) {
00422
00423 emit numUnreadMsgsChanged( folder() );
00424 }else{
00425 if ( !mEmitChangedTimer->isActive() ) {
00426
00427 mEmitChangedTimer->start( 3000 );
00428 }
00429 mChanged = true;
00430 }
00431 }
00432 --mTotalMsgs;
00433
00434 mSize = -1;
00435 QString msgIdMD5 = mb->msgIdMD5();
00436
00437 emit msgRemoved( idx, msgIdMD5 );
00438 emit msgRemoved( folder() );
00439 }
00440
00441
00442
00443 KMMessage* FolderStorage::take(int idx)
00444 {
00445 KMMsgBase* mb;
00446 KMMessage* msg;
00447
00448 assert(idx>=0 && idx<=count());
00449
00450 mb = getMsgBase(idx);
00451 if (!mb) return 0;
00452 if (!mb->isMessage()) readMsg(idx);
00453 Q_UINT32 serNum = KMMsgDict::instance()->getMsgSerNum( folder(), idx );
00454 emit msgRemoved( folder(), serNum );
00455
00456 msg = (KMMessage*)takeIndexEntry(idx);
00457
00458 if (msg->isUnread() || msg->isNew() ||
00459 ( folder() == kmkernel->outboxFolder() )) {
00460 --mUnreadMsgs;
00461 if ( !mQuiet ) {
00462 emit numUnreadMsgsChanged( folder() );
00463 }else{
00464 if ( !mEmitChangedTimer->isActive() ) {
00465 mEmitChangedTimer->start( 3000 );
00466 }
00467 mChanged = true;
00468 }
00469 }
00470 --mTotalMsgs;
00471 msg->setParent(0);
00472 setDirty( true );
00473 mSize = -1;
00474 needsCompact=true;
00475 QString msgIdMD5 = msg->msgIdMD5();
00476 emit msgRemoved( idx, msgIdMD5 );
00477 emit msgRemoved( folder() );
00478
00479 return msg;
00480 }
00481
00482 void FolderStorage::take(QPtrList<KMMessage> msgList)
00483 {
00484 for ( KMMessage* msg = msgList.first(); msg; msg = msgList.next() )
00485 {
00486 if (msg->parent())
00487 {
00488 int idx = msg->parent()->find(msg);
00489 if ( idx >= 0 )
00490 take(idx);
00491 }
00492 }
00493 }
00494
00495
00496
00497 KMMessage* FolderStorage::getMsg(int idx)
00498 {
00499 if ( mOpenCount <= 0 ) {
00500 kdWarning(5006) << "FolderStorage::getMsg was called on a closed folder: " << folder()->prettyURL() << endl;
00501 return 0;
00502 }
00503 if ( idx < 0 || idx >= count() ) {
00504 kdWarning(5006) << "FolderStorage::getMsg was asked for an invalid index. idx =" << idx << " count()=" << count() << endl;
00505 return 0;
00506 }
00507
00508 KMMsgBase* mb = getMsgBase(idx);
00509 if (!mb) {
00510 kdWarning(5006) << "FolderStorage::getMsg, getMsgBase failed for index: " << idx << endl;
00511 return 0;
00512 }
00513
00514 KMMessage *msg = 0;
00515 bool undo = mb->enableUndo();
00516 if (mb->isMessage()) {
00517 msg = ((KMMessage*)mb);
00518 } else {
00519 QString mbSubject = mb->subject();
00520 msg = readMsg(idx);
00521
00522 if (mCompactable && (!msg || (msg->subject().isEmpty() != mbSubject.isEmpty()))) {
00523 kdWarning(5006) << "Error: " << location() <<
00524 " Index file is inconsistent with folder file. This should never happen." << endl;
00525
00526
00527
00528
00529 mCompactable = false;
00530 writeConfig();
00531 }
00532
00533 }
00534
00535
00536
00537 if ( msg->getMsgSerNum() == 0 ) {
00538 kdWarning(5006) << "FolderStorage::getMsg, message has no sernum, index: " << idx << endl;
00539 return 0;
00540 }
00541 msg->setEnableUndo(undo);
00542 msg->setComplete( true );
00543 return msg;
00544 }
00545
00546
00547 KMMessage* FolderStorage::readTemporaryMsg(int idx)
00548 {
00549 if(!(idx >= 0 && idx <= count())) {
00550 kdDebug(5006) << k_funcinfo << "Invalid index " << idx << "!" << endl;
00551 return 0;
00552 }
00553
00554 KMMsgBase* mb = getMsgBase(idx);
00555 if (!mb) {
00556 kdDebug(5006) << k_funcinfo << "getMsgBase() for " << idx << " failed!" << endl;
00557 return 0;
00558 }
00559
00560 unsigned long sernum = mb->getMsgSerNum();
00561
00562 KMMessage *msg = 0;
00563 bool undo = mb->enableUndo();
00564 if (mb->isMessage()) {
00565
00566 msg = new KMMessage(*(KMMessage*)mb);
00567 msg->setMsgSerNum(sernum);
00568 msg->setComplete( true );
00569 } else {
00570
00571 msg = new KMMessage(*(KMMsgInfo*)mb);
00572 msg->setMsgSerNum(sernum);
00573 msg->setComplete( true );
00574 const DwString msgString = getDwString( idx );
00575 if ( msgString.size() <= 0 ) {
00576 kdDebug(5006) << k_funcinfo << " Calling getDwString() failed!" << endl;
00577 }
00578 msg->fromDwString( msgString );
00579 }
00580 msg->setEnableUndo(undo);
00581 return msg;
00582 }
00583
00584
00585
00586 KMMsgInfo* FolderStorage::unGetMsg(int idx)
00587 {
00588 KMMsgBase* mb;
00589
00590 if(!(idx >= 0 && idx <= count()))
00591 return 0;
00592
00593 mb = getMsgBase(idx);
00594 if (!mb) return 0;
00595
00596
00597 if (mb->isMessage()) {
00598
00599
00600 KMMessage *msg = static_cast<KMMessage*>(mb);
00601 if ( msg->transferInProgress() ) return 0;
00602 ignoreJobsForMessage( msg );
00603 return setIndexEntry( idx, msg );
00604 }
00605
00606 return 0;
00607 }
00608
00609
00610
00611 bool FolderStorage::isMessage(int idx)
00612 {
00613 KMMsgBase* mb;
00614 if (!(idx >= 0 && idx <= count())) return false;
00615 mb = getMsgBase(idx);
00616 return (mb && mb->isMessage());
00617 }
00618
00619
00620 FolderJob* FolderStorage::createJob( KMMessage *msg, FolderJob::JobType jt,
00621 KMFolder *folder, QString partSpecifier,
00622 const AttachmentStrategy *as ) const
00623 {
00624 FolderJob * job = doCreateJob( msg, jt, folder, partSpecifier, as );
00625 if ( job )
00626 addJob( job );
00627 return job;
00628 }
00629
00630
00631 FolderJob* FolderStorage::createJob( QPtrList<KMMessage>& msgList, const QString& sets,
00632 FolderJob::JobType jt, KMFolder *folder ) const
00633 {
00634 FolderJob * job = doCreateJob( msgList, sets, jt, folder );
00635 if ( job )
00636 addJob( job );
00637 return job;
00638 }
00639
00640
00641 int FolderStorage::moveMsg(KMMessage* aMsg, int* aIndex_ret)
00642 {
00643 assert(aMsg != 0);
00644 KMFolder* msgParent = aMsg->parent();
00645
00646 if (msgParent)
00647 msgParent->open("moveMsgSrc");
00648
00649 open("moveMsgDest");
00650 int rc = addMsg(aMsg, aIndex_ret);
00651 close("moveMsgDest");
00652
00653 if (msgParent)
00654 msgParent->close("moveMsgSrc");
00655
00656 return rc;
00657 }
00658
00659
00660 int FolderStorage::moveMsg(QPtrList<KMMessage> msglist, int* aIndex_ret)
00661 {
00662 KMMessage* aMsg = msglist.first();
00663 assert(aMsg != 0);
00664 KMFolder* msgParent = aMsg->parent();
00665
00666 if (msgParent)
00667 msgParent->open("foldermovemsg");
00668
00669 QValueList<int> index;
00670 open("moveMsg");
00671 int rc = addMsg(msglist, index);
00672 close("moveMsg");
00673
00674 if ( !index.isEmpty() )
00675 aIndex_ret = &index.first();
00676
00677 if (msgParent)
00678 msgParent->close("foldermovemsg");
00679
00680 return rc;
00681 }
00682
00683
00684
00685 int FolderStorage::rename(const QString& newName, KMFolderDir *newParent)
00686 {
00687 QString oldLoc, oldIndexLoc, oldIdsLoc, newLoc, newIndexLoc, newIdsLoc;
00688 QString oldSubDirLoc, newSubDirLoc;
00689 QString oldName;
00690 int rc=0;
00691 KMFolderDir *oldParent;
00692
00693 assert(!newName.isEmpty());
00694
00695 oldLoc = location();
00696 oldIndexLoc = indexLocation();
00697 oldSubDirLoc = folder()->subdirLocation();
00698 oldIdsLoc = KMMsgDict::instance()->getFolderIdsLocation( *this );
00699 QString oldConfigString = "Folder-" + folder()->idString();
00700
00701 close("rename", true);
00702
00703 oldName = folder()->fileName();
00704 oldParent = folder()->parent();
00705 if (newParent)
00706 folder()->setParent( newParent );
00707
00708 folder()->setName(newName);
00709 newLoc = location();
00710 newIndexLoc = indexLocation();
00711 newSubDirLoc = folder()->subdirLocation();
00712 newIdsLoc = KMMsgDict::instance()->getFolderIdsLocation( *this );
00713
00714 if (::rename(QFile::encodeName(oldLoc), QFile::encodeName(newLoc))) {
00715 folder()->setName(oldName);
00716 folder()->setParent(oldParent);
00717 rc = errno;
00718 }
00719 else {
00720
00721 if (!oldIndexLoc.isEmpty()) {
00722 ::rename(QFile::encodeName(oldIndexLoc), QFile::encodeName(newIndexLoc));
00723 ::rename(QFile::encodeName(oldIndexLoc) + ".sorted",
00724 QFile::encodeName(newIndexLoc) + ".sorted");
00725 }
00726
00727
00728 if (!oldIdsLoc.isEmpty())
00729 ::rename(QFile::encodeName(oldIdsLoc), QFile::encodeName(newIdsLoc));
00730
00731
00732 KMFolderDir* child = 0;
00733 if( folder() )
00734 child = folder()->child();
00735
00736 if (!::rename(QFile::encodeName(oldSubDirLoc), QFile::encodeName(newSubDirLoc) )) {
00737
00738
00739
00740 if( child && ( oldName != newName ) ) {
00741 child->setName( "." + QFile::encodeName(newName) + ".directory" );
00742 }
00743 }
00744
00745
00746
00747 if (newParent) {
00748 if (oldParent->findRef( folder() ) != -1)
00749 oldParent->take();
00750 newParent->inSort( folder() );
00751 if ( child ) {
00752 if ( child->parent()->findRef( child ) != -1 )
00753 child->parent()->take();
00754 newParent->inSort( child );
00755 child->setParent( newParent );
00756 }
00757 }
00758 }
00759
00760 writeConfig();
00761
00762
00763 if ( oldConfigString != "Folder-" + folder()->idString() )
00764 KMKernel::config()->deleteGroup( oldConfigString );
00765
00766 emit locationChanged( oldLoc, newLoc );
00767 emit nameChanged();
00768 kmkernel->folderMgr()->contentsChanged();
00769 emit closed(folder());
00770 return rc;
00771 }
00772
00773
00774
00775 void FolderStorage::remove()
00776 {
00777 assert(!folder()->name().isEmpty());
00778
00779 clearIndex( true, mExportsSernums );
00780 close("remove", true);
00781
00782 if ( mExportsSernums ) {
00783 KMMsgDict::mutableInstance()->removeFolderIds( *this );
00784 mExportsSernums = false;
00785 }
00786 unlink(QFile::encodeName(indexLocation()) + ".sorted");
00787 unlink(QFile::encodeName(indexLocation()));
00788
00789 int rc = removeContents();
00790
00791 needsCompact = false;
00792
00793
00794 KConfig* config = KMKernel::config();
00795 config->deleteGroup( "Folder-" + folder()->idString() );
00796
00797 emit closed(folder());
00798 emit removed(folder(), (rc ? false : true));
00799 }
00800
00801
00802
00803 int FolderStorage::expunge()
00804 {
00805 assert(!folder()->name().isEmpty());
00806
00807 clearIndex( true, mExportsSernums );
00808 close( "expunge", true );
00809
00810 if ( mExportsSernums )
00811 KMMsgDict::mutableInstance()->removeFolderIds( *this );
00812 if ( mAutoCreateIndex )
00813 truncateIndex();
00814 else unlink(QFile::encodeName(indexLocation()));
00815
00816 int rc = expungeContents();
00817 if (rc) return rc;
00818
00819 mDirty = false;
00820 needsCompact = false;
00821
00822 mUnreadMsgs = 0;
00823 mTotalMsgs = 0;
00824 mSize = 0;
00825 emit numUnreadMsgsChanged( folder() );
00826 if ( mAutoCreateIndex )
00827 writeConfig();
00828 emit changed();
00829 emit expunged( folder() );
00830
00831 return 0;
00832 }
00833
00834
00835 QString FolderStorage::label() const
00836 {
00837 return folder()->label();
00838 }
00839
00840 int FolderStorage::count(bool cache) const
00841 {
00842 if (cache && mTotalMsgs != -1)
00843 return mTotalMsgs;
00844 else
00845 return -1;
00846 }
00847
00848
00849 int FolderStorage::countUnread()
00850 {
00851 if (mGuessedUnreadMsgs > -1)
00852 return mGuessedUnreadMsgs;
00853 if (mUnreadMsgs > -1)
00854 return mUnreadMsgs;
00855
00856 readConfig();
00857
00858 if (mUnreadMsgs > -1)
00859 return mUnreadMsgs;
00860
00861 open("countunread");
00862 int unread = mUnreadMsgs;
00863 close("countunread");
00864 return (unread > 0) ? unread : 0;
00865 }
00866
00867 Q_INT64 FolderStorage::folderSize() const
00868 {
00869 if ( mSize != -1 ) {
00870 return mSize;
00871 } else {
00872 return doFolderSize();
00873 }
00874 }
00875
00876
00877
00878 bool FolderStorage::isCloseToQuota() const
00879 {
00880 return false;
00881 }
00882
00883
00884 void FolderStorage::msgStatusChanged(const KMMsgStatus oldStatus,
00885 const KMMsgStatus newStatus, int idx)
00886 {
00887 int oldUnread = 0;
00888 int newUnread = 0;
00889
00890 if (((oldStatus & KMMsgStatusUnread || oldStatus & KMMsgStatusNew) &&
00891 !(oldStatus & KMMsgStatusIgnored)) ||
00892 (folder() == kmkernel->outboxFolder()))
00893 oldUnread = 1;
00894 if (((newStatus & KMMsgStatusUnread || newStatus & KMMsgStatusNew) &&
00895 !(newStatus & KMMsgStatusIgnored)) ||
00896 (folder() == kmkernel->outboxFolder()))
00897 newUnread = 1;
00898 int deltaUnread = newUnread - oldUnread;
00899
00900 mDirtyTimer->changeInterval(mDirtyTimerInterval);
00901 if (deltaUnread != 0) {
00902 if (mUnreadMsgs < 0) mUnreadMsgs = 0;
00903 mUnreadMsgs += deltaUnread;
00904 if ( !mQuiet ) {
00905 emit numUnreadMsgsChanged( folder() );
00906 }else{
00907 if ( !mEmitChangedTimer->isActive() ) {
00908 mEmitChangedTimer->start( 3000 );
00909 }
00910 mChanged = true;
00911 }
00912 Q_UINT32 serNum = KMMsgDict::instance()->getMsgSerNum(folder(), idx);
00913 emit msgChanged( folder(), serNum, deltaUnread );
00914 }
00915 }
00916
00917
00918 void FolderStorage::headerOfMsgChanged(const KMMsgBase* aMsg, int idx)
00919 {
00920 if (idx < 0)
00921 idx = aMsg->parent()->find( aMsg );
00922
00923 if (idx >= 0 )
00924 {
00925 if ( !mQuiet )
00926 emit msgHeaderChanged(folder(), idx);
00927 else{
00928 if ( !mEmitChangedTimer->isActive() ) {
00929 mEmitChangedTimer->start( 3000 );
00930 }
00931 mChanged = true;
00932 }
00933 } else
00934 mChanged = true;
00935 }
00936
00937
00938 void FolderStorage::readConfig()
00939 {
00940
00941 KConfig* config = KMKernel::config();
00942 KConfigGroupSaver saver(config, "Folder-" + folder()->idString());
00943 if (mUnreadMsgs == -1)
00944 mUnreadMsgs = config->readNumEntry("UnreadMsgs", -1);
00945 if (mTotalMsgs == -1)
00946 mTotalMsgs = config->readNumEntry("TotalMsgs", -1);
00947 mCompactable = config->readBoolEntry("Compactable", true);
00948 if ( mSize == -1 )
00949 mSize = config->readNum64Entry("FolderSize", -1);
00950
00951 int type = config->readNumEntry( "ContentsType", 0 );
00952 if ( type < 0 || type > KMail::ContentsTypeLast ) type = 0;
00953 setContentsType( static_cast<KMail::FolderContentsType>( type ) );
00954
00955 if( folder() ) folder()->readConfig( config );
00956 }
00957
00958
00959 void FolderStorage::writeConfig()
00960 {
00961 KConfig* config = KMKernel::config();
00962 KConfigGroupSaver saver(config, "Folder-" + folder()->idString());
00963 config->writeEntry("UnreadMsgs",
00964 mGuessedUnreadMsgs == -1 ? mUnreadMsgs : mGuessedUnreadMsgs);
00965 config->writeEntry("TotalMsgs", mTotalMsgs);
00966 config->writeEntry("Compactable", mCompactable);
00967 config->writeEntry("ContentsType", mContentsType);
00968 config->writeEntry("FolderSize", mSize);
00969
00970
00971 if( folder() ) folder()->writeConfig( config );
00972
00973 GlobalSettings::self()->requestSync();
00974 }
00975
00976
00977 void FolderStorage::correctUnreadMsgsCount()
00978 {
00979 open("countunreadmsg");
00980 close("countunreadmsg");
00981 emit numUnreadMsgsChanged( folder() );
00982 }
00983
00984 void FolderStorage::registerWithMessageDict()
00985 {
00986 mExportsSernums = true;
00987 readFolderIdsFile();
00988 }
00989
00990 void FolderStorage::deregisterFromMessageDict()
00991 {
00992 writeFolderIdsFile();
00993 mExportsSernums = false;
00994 }
00995
00996 void FolderStorage::readFolderIdsFile()
00997 {
00998 if ( !mExportsSernums ) return;
00999 if ( KMMsgDict::mutableInstance()->readFolderIds( *this ) == -1 ) {
01000 invalidateFolder();
01001 }
01002 if ( !KMMsgDict::mutableInstance()->hasFolderIds( *this ) ) {
01003 invalidateFolder();
01004 }
01005 }
01006
01007 void FolderStorage::invalidateFolder()
01008 {
01009 if ( !mExportsSernums ) return;
01010 unlink(QFile::encodeName( indexLocation()) + ".sorted");
01011 unlink(QFile::encodeName( indexLocation()) + ".ids");
01012 fillMessageDict();
01013 KMMsgDict::mutableInstance()->writeFolderIds( *this );
01014 emit invalidated( folder() );
01015 }
01016
01017
01018
01019 int FolderStorage::writeFolderIdsFile() const
01020 {
01021 if ( !mExportsSernums ) return -1;
01022 return KMMsgDict::mutableInstance()->writeFolderIds( *this );
01023 }
01024
01025
01026 int FolderStorage::touchFolderIdsFile()
01027 {
01028 if ( !mExportsSernums ) return -1;
01029 return KMMsgDict::mutableInstance()->touchFolderIds( *this );
01030 }
01031
01032
01033 int FolderStorage::appendToFolderIdsFile( int idx )
01034 {
01035 if ( !mExportsSernums ) return -1;
01036 int ret = 0;
01037 if ( count() == 1 ) {
01038 ret = KMMsgDict::mutableInstance()->writeFolderIds( *this );
01039 } else {
01040 ret = KMMsgDict::mutableInstance()->appendToFolderIds( *this, idx );
01041 }
01042 return ret;
01043 }
01044
01045 void FolderStorage::replaceMsgSerNum( unsigned long sernum, KMMsgBase* msg, int idx )
01046 {
01047 if ( !mExportsSernums ) return;
01048 KMMsgDict::mutableInstance()->replace( sernum, msg, idx );
01049 }
01050
01051 void FolderStorage::setRDict( KMMsgDictREntry *rentry ) const
01052 {
01053 if ( ! mExportsSernums )
01054 kdDebug(5006) << "WTF, this FolderStorage should be invisible to the msgdict, who is calling us?" << kdBacktrace() << endl;
01055 assert( mExportsSernums );
01056 if ( rentry == mRDict )
01057 return;
01058 KMMsgDict::deleteRentry( mRDict );
01059 mRDict = rentry;
01060 }
01061
01062
01063 void FolderStorage::setStatus(int idx, KMMsgStatus status, bool toggle)
01064 {
01065 KMMsgBase *msg = getMsgBase(idx);
01066 if ( msg ) {
01067 if (toggle)
01068 msg->toggleStatus(status, idx);
01069 else
01070 msg->setStatus(status, idx);
01071 }
01072 }
01073
01074
01075
01076 void FolderStorage::setStatus(QValueList<int>& ids, KMMsgStatus status, bool toggle)
01077 {
01078 for ( QValueList<int>::Iterator it = ids.begin(); it != ids.end(); ++it )
01079 {
01080 FolderStorage::setStatus(*it, status, toggle);
01081 }
01082 }
01083
01084 void FolderStorage::ignoreJobsForMessage( KMMessage *msg )
01085 {
01086 if ( !msg || msg->transferInProgress() )
01087 return;
01088
01089 QPtrListIterator<FolderJob> it( mJobList );
01090 while ( it.current() )
01091 {
01092
01093
01094
01095 if ( it.current()->msgList().first() == msg )
01096 {
01097 FolderJob* job = it.current();
01098 mJobList.remove( job );
01099 delete job;
01100 } else
01101 ++it;
01102 }
01103 }
01104
01105
01106 void FolderStorage::removeJobs()
01107 {
01108 mJobList.setAutoDelete( true );
01109 mJobList.clear();
01110 mJobList.setAutoDelete( false );
01111 }
01112
01113
01114
01115
01116 void FolderStorage::updateChildrenState()
01117 {
01118 if ( folder() && folder()->child() )
01119 {
01120 if ( kmkernel->folderMgr()->folderCount( folder()->child() ) > 0 )
01121 setHasChildren( HasChildren );
01122 else
01123 setHasChildren( HasNoChildren );
01124 }
01125 }
01126
01127
01128 void FolderStorage::setNoChildren( bool aNoChildren )
01129 {
01130 mNoChildren = aNoChildren;
01131 if ( aNoChildren )
01132 setHasChildren( HasNoChildren );
01133 }
01134
01135
01136 void FolderStorage::setContentsType( KMail::FolderContentsType type, bool quiet )
01137 {
01138 if ( type != mContentsType ) {
01139 mContentsType = type;
01140 if ( !quiet )
01141 emit contentsTypeChanged( type );
01142 }
01143 }
01144
01145
01146 void FolderStorage::search( const KMSearchPattern* pattern )
01147 {
01148 mSearchPattern = pattern;
01149 mCurrentSearchedMsg = 0;
01150 if ( pattern )
01151 slotProcessNextSearchBatch();
01152 }
01153
01154 void FolderStorage::slotProcessNextSearchBatch()
01155 {
01156 if ( !mSearchPattern )
01157 return;
01158 QValueList<Q_UINT32> matchingSerNums;
01159 const int end = QMIN( mCurrentSearchedMsg + 15, count() );
01160 for ( int i = mCurrentSearchedMsg; i < end; ++i )
01161 {
01162 Q_UINT32 serNum = KMMsgDict::instance()->getMsgSerNum( folder(), i );
01163 if ( mSearchPattern->matches( serNum ) )
01164 matchingSerNums.append( serNum );
01165 }
01166 mCurrentSearchedMsg = end;
01167 bool complete = ( end >= count() );
01168 emit searchResult( folder(), matchingSerNums, mSearchPattern, complete );
01169 if ( !complete )
01170 QTimer::singleShot( 0, this, SLOT(slotProcessNextSearchBatch()) );
01171 }
01172
01173
01174 void FolderStorage::search( const KMSearchPattern* pattern, Q_UINT32 serNum )
01175 {
01176 bool matches = pattern && pattern->matches( serNum );
01177
01178 emit searchDone( folder(), serNum, pattern, matches );
01179 }
01180
01181
01182 int FolderStorage::addMsg( QPtrList<KMMessage>& msgList, QValueList<int>& index_ret )
01183 {
01184 int ret = 0;
01185 int index;
01186 for ( QPtrListIterator<KMMessage> it( msgList ); *it; ++it )
01187 {
01188 int aret = addMsg( *it, &index );
01189 index_ret << index;
01190 if ( aret != 0 )
01191 ret = aret;
01192 }
01193 return ret;
01194 }
01195
01196
01197 bool FolderStorage::isMoveable() const
01198 {
01199 return ( folder()->isSystemFolder() ) ? false : true;
01200 }
01201
01202
01203
01204 KMAccount* FolderStorage::account() const
01205 {
01206 return 0;
01207 }
01208
01209 bool FolderStorage::mailCheckInProgress() const
01210 {
01211 return false;
01212 }
01213
01214 bool FolderStorage::canDeleteMessages() const
01215 {
01216 return !isReadOnly();
01217 }
01218
01219 void FolderStorage::setNoContent(bool aNoContent)
01220 {
01221 const bool changed = aNoContent != mNoContent;
01222 mNoContent = aNoContent;
01223 if ( changed )
01224 emit noContentChanged();
01225 }
01226
01227 #include "folderstorage.moc"