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 if(idx < 0)
00402 {
00403 kdDebug(5006) << "FolderStorage::removeMsg() : idx < 0\n" << endl;
00404 return;
00405 }
00406
00407 KMMsgBase* mb = getMsgBase(idx);
00408
00409 Q_UINT32 serNum = KMMsgDict::instance()->getMsgSerNum( folder(), idx );
00410 if (serNum != 0)
00411 emit msgRemoved( folder(), serNum );
00412 mb = takeIndexEntry( idx );
00413
00414 setDirty( true );
00415 needsCompact=true;
00416
00417 if (mb->isUnread() || mb->isNew() ||
00418 (folder() == kmkernel->outboxFolder())) {
00419 --mUnreadMsgs;
00420 if ( !mQuiet ) {
00421
00422 emit numUnreadMsgsChanged( folder() );
00423 }else{
00424 if ( !mEmitChangedTimer->isActive() ) {
00425
00426 mEmitChangedTimer->start( 3000 );
00427 }
00428 mChanged = true;
00429 }
00430 }
00431 --mTotalMsgs;
00432
00433 mSize = -1;
00434 QString msgIdMD5 = mb->msgIdMD5();
00435 emit msgRemoved( idx, msgIdMD5 );
00436 emit msgRemoved( folder() );
00437 }
00438
00439
00440
00441 KMMessage* FolderStorage::take(int idx)
00442 {
00443 KMMsgBase* mb;
00444 KMMessage* msg;
00445
00446 assert(idx>=0 && idx<=count());
00447
00448 mb = getMsgBase(idx);
00449 if (!mb) return 0;
00450 if (!mb->isMessage()) readMsg(idx);
00451 Q_UINT32 serNum = KMMsgDict::instance()->getMsgSerNum( folder(), idx );
00452 emit msgRemoved( folder(), serNum );
00453
00454 msg = (KMMessage*)takeIndexEntry(idx);
00455
00456 if (msg->isUnread() || msg->isNew() ||
00457 ( folder() == kmkernel->outboxFolder() )) {
00458 --mUnreadMsgs;
00459 if ( !mQuiet ) {
00460 emit numUnreadMsgsChanged( folder() );
00461 }else{
00462 if ( !mEmitChangedTimer->isActive() ) {
00463 mEmitChangedTimer->start( 3000 );
00464 }
00465 mChanged = true;
00466 }
00467 }
00468 --mTotalMsgs;
00469 msg->setParent(0);
00470 setDirty( true );
00471 mSize = -1;
00472 needsCompact=true;
00473 QString msgIdMD5 = msg->msgIdMD5();
00474 emit msgRemoved( idx, msgIdMD5 );
00475 emit msgRemoved( folder() );
00476
00477 return msg;
00478 }
00479
00480 void FolderStorage::take(QPtrList<KMMessage> msgList)
00481 {
00482 for ( KMMessage* msg = msgList.first(); msg; msg = msgList.next() )
00483 {
00484 if (msg->parent())
00485 {
00486 int idx = msg->parent()->find(msg);
00487 if ( idx >= 0 )
00488 take(idx);
00489 }
00490 }
00491 }
00492
00493
00494
00495 KMMessage* FolderStorage::getMsg(int idx)
00496 {
00497 if ( mOpenCount <= 0 ) {
00498 kdWarning(5006) << "FolderStorage::getMsg was called on a closed folder: " << folder()->prettyURL() << endl;
00499 return 0;
00500 }
00501 if ( idx < 0 || idx >= count() ) {
00502 kdWarning(5006) << "FolderStorage::getMsg was asked for an invalid index. idx =" << idx << " count()=" << count() << endl;
00503 return 0;
00504 }
00505
00506 KMMsgBase* mb = getMsgBase(idx);
00507 if (!mb) {
00508 kdWarning(5006) << "FolderStorage::getMsg, getMsgBase failed for index: " << idx << endl;
00509 return 0;
00510 }
00511
00512 KMMessage *msg = 0;
00513 bool undo = mb->enableUndo();
00514 if (mb->isMessage()) {
00515 msg = ((KMMessage*)mb);
00516 } else {
00517 QString mbSubject = mb->subject();
00518 msg = readMsg(idx);
00519
00520 if (mCompactable && (!msg || (msg->subject().isEmpty() != mbSubject.isEmpty()))) {
00521 kdWarning(5006) << "Error: " << location() <<
00522 " Index file is inconsistent with folder file. This should never happen." << endl;
00523
00524
00525
00526
00527 mCompactable = false;
00528 writeConfig();
00529 }
00530
00531 }
00532
00533
00534
00535 if ( msg->getMsgSerNum() == 0 ) {
00536 kdWarning(5006) << "FolderStorage::getMsg, message has no sernum, index: " << idx << endl;
00537 return 0;
00538 }
00539 msg->setEnableUndo(undo);
00540 msg->setComplete( true );
00541 return msg;
00542 }
00543
00544
00545 KMMessage* FolderStorage::readTemporaryMsg(int idx)
00546 {
00547 if(!(idx >= 0 && idx <= count())) {
00548 kdDebug(5006) << k_funcinfo << "Invalid index " << idx << "!" << endl;
00549 return 0;
00550 }
00551
00552 KMMsgBase* mb = getMsgBase(idx);
00553 if (!mb) {
00554 kdDebug(5006) << k_funcinfo << "getMsgBase() for " << idx << " failed!" << endl;
00555 return 0;
00556 }
00557
00558 unsigned long sernum = mb->getMsgSerNum();
00559
00560 KMMessage *msg = 0;
00561 bool undo = mb->enableUndo();
00562 if (mb->isMessage()) {
00563
00564 msg = new KMMessage(*(KMMessage*)mb);
00565 msg->setMsgSerNum(sernum);
00566 msg->setComplete( true );
00567 } else {
00568
00569 msg = new KMMessage(*(KMMsgInfo*)mb);
00570 msg->setMsgSerNum(sernum);
00571 msg->setComplete( true );
00572 const DwString msgString = getDwString( idx );
00573 if ( msgString.size() <= 0 ) {
00574 kdDebug(5006) << k_funcinfo << " Calling getDwString() failed!" << endl;
00575 }
00576 msg->fromDwString( msgString );
00577 }
00578 msg->setEnableUndo(undo);
00579 return msg;
00580 }
00581
00582
00583
00584 KMMsgInfo* FolderStorage::unGetMsg(int idx)
00585 {
00586 KMMsgBase* mb;
00587
00588 if(!(idx >= 0 && idx <= count()))
00589 return 0;
00590
00591 mb = getMsgBase(idx);
00592 if (!mb) return 0;
00593
00594
00595 if (mb->isMessage()) {
00596
00597
00598 KMMessage *msg = static_cast<KMMessage*>(mb);
00599 if ( msg->transferInProgress() ) return 0;
00600 ignoreJobsForMessage( msg );
00601 return setIndexEntry( idx, msg );
00602 }
00603
00604 return 0;
00605 }
00606
00607
00608
00609 bool FolderStorage::isMessage(int idx)
00610 {
00611 KMMsgBase* mb;
00612 if (!(idx >= 0 && idx <= count())) return false;
00613 mb = getMsgBase(idx);
00614 return (mb && mb->isMessage());
00615 }
00616
00617
00618 FolderJob* FolderStorage::createJob( KMMessage *msg, FolderJob::JobType jt,
00619 KMFolder *folder, QString partSpecifier,
00620 const AttachmentStrategy *as ) const
00621 {
00622 FolderJob * job = doCreateJob( msg, jt, folder, partSpecifier, as );
00623 if ( job )
00624 addJob( job );
00625 return job;
00626 }
00627
00628
00629 FolderJob* FolderStorage::createJob( QPtrList<KMMessage>& msgList, const QString& sets,
00630 FolderJob::JobType jt, KMFolder *folder ) const
00631 {
00632 FolderJob * job = doCreateJob( msgList, sets, jt, folder );
00633 if ( job )
00634 addJob( job );
00635 return job;
00636 }
00637
00638
00639 int FolderStorage::moveMsg(KMMessage* aMsg, int* aIndex_ret)
00640 {
00641 assert(aMsg != 0);
00642 KMFolder* msgParent = aMsg->parent();
00643
00644 if (msgParent)
00645 msgParent->open("moveMsgSrc");
00646
00647 open("moveMsgDest");
00648 int rc = addMsg(aMsg, aIndex_ret);
00649 close("moveMsgDest");
00650
00651 if (msgParent)
00652 msgParent->close("moveMsgSrc");
00653
00654 return rc;
00655 }
00656
00657
00658 int FolderStorage::moveMsg(QPtrList<KMMessage> msglist, int* aIndex_ret)
00659 {
00660 KMMessage* aMsg = msglist.first();
00661 assert(aMsg != 0);
00662 KMFolder* msgParent = aMsg->parent();
00663
00664 if (msgParent)
00665 msgParent->open("foldermovemsg");
00666
00667 QValueList<int> index;
00668 open("moveMsg");
00669 int rc = addMsg(msglist, index);
00670 close("moveMsg");
00671
00672 if ( !index.isEmpty() )
00673 aIndex_ret = &index.first();
00674
00675 if (msgParent)
00676 msgParent->close("foldermovemsg");
00677
00678 return rc;
00679 }
00680
00681
00682
00683 int FolderStorage::rename(const QString& newName, KMFolderDir *newParent)
00684 {
00685 QString oldLoc, oldIndexLoc, oldIdsLoc, newLoc, newIndexLoc, newIdsLoc;
00686 QString oldSubDirLoc, newSubDirLoc;
00687 QString oldName;
00688 int rc=0;
00689 KMFolderDir *oldParent;
00690
00691 assert(!newName.isEmpty());
00692
00693 oldLoc = location();
00694 oldIndexLoc = indexLocation();
00695 oldSubDirLoc = folder()->subdirLocation();
00696 oldIdsLoc = KMMsgDict::instance()->getFolderIdsLocation( *this );
00697 QString oldConfigString = "Folder-" + folder()->idString();
00698
00699 close("rename", true);
00700
00701 oldName = folder()->fileName();
00702 oldParent = folder()->parent();
00703 if (newParent)
00704 folder()->setParent( newParent );
00705
00706 folder()->setName(newName);
00707 newLoc = location();
00708 newIndexLoc = indexLocation();
00709 newSubDirLoc = folder()->subdirLocation();
00710 newIdsLoc = KMMsgDict::instance()->getFolderIdsLocation( *this );
00711
00712 if (::rename(QFile::encodeName(oldLoc), QFile::encodeName(newLoc))) {
00713 folder()->setName(oldName);
00714 folder()->setParent(oldParent);
00715 rc = errno;
00716 }
00717 else {
00718
00719 if (!oldIndexLoc.isEmpty()) {
00720 ::rename(QFile::encodeName(oldIndexLoc), QFile::encodeName(newIndexLoc));
00721 ::rename(QFile::encodeName(oldIndexLoc) + ".sorted",
00722 QFile::encodeName(newIndexLoc) + ".sorted");
00723 }
00724
00725
00726 if (!oldIdsLoc.isEmpty())
00727 ::rename(QFile::encodeName(oldIdsLoc), QFile::encodeName(newIdsLoc));
00728
00729
00730 KMFolderDir* child = 0;
00731 if( folder() )
00732 child = folder()->child();
00733
00734 if (!::rename(QFile::encodeName(oldSubDirLoc), QFile::encodeName(newSubDirLoc) )) {
00735
00736
00737
00738 if( child && ( oldName != newName ) ) {
00739 child->setName( "." + QFile::encodeName(newName) + ".directory" );
00740 }
00741 }
00742
00743
00744
00745 if (newParent) {
00746 if (oldParent->findRef( folder() ) != -1)
00747 oldParent->take();
00748 newParent->inSort( folder() );
00749 if ( child ) {
00750 if ( child->parent()->findRef( child ) != -1 )
00751 child->parent()->take();
00752 newParent->inSort( child );
00753 child->setParent( newParent );
00754 }
00755 }
00756 }
00757
00758 writeConfig();
00759
00760
00761 if ( oldConfigString != "Folder-" + folder()->idString() )
00762 KMKernel::config()->deleteGroup( oldConfigString );
00763
00764 emit locationChanged( oldLoc, newLoc );
00765 emit nameChanged();
00766 kmkernel->folderMgr()->contentsChanged();
00767 emit closed(folder());
00768 return rc;
00769 }
00770
00771
00772
00773 void FolderStorage::remove()
00774 {
00775 assert(!folder()->name().isEmpty());
00776
00777 clearIndex( true, mExportsSernums );
00778 close("remove", true);
00779
00780 if ( mExportsSernums ) {
00781 KMMsgDict::mutableInstance()->removeFolderIds( *this );
00782 mExportsSernums = false;
00783 }
00784 unlink(QFile::encodeName(indexLocation()) + ".sorted");
00785 unlink(QFile::encodeName(indexLocation()));
00786
00787 int rc = removeContents();
00788
00789 needsCompact = false;
00790
00791
00792 KConfig* config = KMKernel::config();
00793 config->deleteGroup( "Folder-" + folder()->idString() );
00794
00795 emit closed(folder());
00796 emit removed(folder(), (rc ? false : true));
00797 }
00798
00799
00800
00801 int FolderStorage::expunge()
00802 {
00803 assert(!folder()->name().isEmpty());
00804
00805 clearIndex( true, mExportsSernums );
00806 close( "expunge", true );
00807
00808 if ( mExportsSernums )
00809 KMMsgDict::mutableInstance()->removeFolderIds( *this );
00810 if ( mAutoCreateIndex )
00811 truncateIndex();
00812 else unlink(QFile::encodeName(indexLocation()));
00813
00814 int rc = expungeContents();
00815 if (rc) return rc;
00816
00817 mDirty = false;
00818 needsCompact = false;
00819
00820 mUnreadMsgs = 0;
00821 mTotalMsgs = 0;
00822 mSize = 0;
00823 emit numUnreadMsgsChanged( folder() );
00824 if ( mAutoCreateIndex )
00825 writeConfig();
00826 emit changed();
00827 emit expunged( folder() );
00828
00829 return 0;
00830 }
00831
00832
00833 QString FolderStorage::label() const
00834 {
00835 return folder()->label();
00836 }
00837
00838 int FolderStorage::count(bool cache) const
00839 {
00840 if (cache && mTotalMsgs != -1)
00841 return mTotalMsgs;
00842 else
00843 return -1;
00844 }
00845
00846
00847 int FolderStorage::countUnread()
00848 {
00849 if (mGuessedUnreadMsgs > -1)
00850 return mGuessedUnreadMsgs;
00851 if (mUnreadMsgs > -1)
00852 return mUnreadMsgs;
00853
00854 readConfig();
00855
00856 if (mUnreadMsgs > -1)
00857 return mUnreadMsgs;
00858
00859 open("countunread");
00860 int unread = mUnreadMsgs;
00861 close("countunread");
00862 return (unread > 0) ? unread : 0;
00863 }
00864
00865 Q_INT64 FolderStorage::folderSize() const
00866 {
00867 if ( mSize != -1 ) {
00868 return mSize;
00869 } else {
00870 return doFolderSize();
00871 }
00872 }
00873
00874
00875
00876 bool FolderStorage::isCloseToQuota() const
00877 {
00878 return false;
00879 }
00880
00881
00882 void FolderStorage::msgStatusChanged(const KMMsgStatus oldStatus,
00883 const KMMsgStatus newStatus, int idx)
00884 {
00885 int oldUnread = 0;
00886 int newUnread = 0;
00887
00888 if (((oldStatus & KMMsgStatusUnread || oldStatus & KMMsgStatusNew) &&
00889 !(oldStatus & KMMsgStatusIgnored)) ||
00890 (folder() == kmkernel->outboxFolder()))
00891 oldUnread = 1;
00892 if (((newStatus & KMMsgStatusUnread || newStatus & KMMsgStatusNew) &&
00893 !(newStatus & KMMsgStatusIgnored)) ||
00894 (folder() == kmkernel->outboxFolder()))
00895 newUnread = 1;
00896 int deltaUnread = newUnread - oldUnread;
00897
00898 mDirtyTimer->changeInterval(mDirtyTimerInterval);
00899 if (deltaUnread != 0) {
00900 if (mUnreadMsgs < 0) mUnreadMsgs = 0;
00901 mUnreadMsgs += deltaUnread;
00902 if ( !mQuiet ) {
00903 emit numUnreadMsgsChanged( folder() );
00904 }else{
00905 if ( !mEmitChangedTimer->isActive() ) {
00906 mEmitChangedTimer->start( 3000 );
00907 }
00908 mChanged = true;
00909 }
00910 Q_UINT32 serNum = KMMsgDict::instance()->getMsgSerNum(folder(), idx);
00911 emit msgChanged( folder(), serNum, deltaUnread );
00912 }
00913 }
00914
00915
00916 void FolderStorage::headerOfMsgChanged(const KMMsgBase* aMsg, int idx)
00917 {
00918 if (idx < 0)
00919 idx = aMsg->parent()->find( aMsg );
00920
00921 if (idx >= 0 )
00922 {
00923 if ( !mQuiet )
00924 emit msgHeaderChanged(folder(), idx);
00925 else{
00926 if ( !mEmitChangedTimer->isActive() ) {
00927 mEmitChangedTimer->start( 3000 );
00928 }
00929 mChanged = true;
00930 }
00931 } else
00932 mChanged = true;
00933 }
00934
00935
00936 void FolderStorage::readConfig()
00937 {
00938
00939 KConfig* config = KMKernel::config();
00940 KConfigGroupSaver saver(config, "Folder-" + folder()->idString());
00941 if (mUnreadMsgs == -1)
00942 mUnreadMsgs = config->readNumEntry("UnreadMsgs", -1);
00943 if (mTotalMsgs == -1)
00944 mTotalMsgs = config->readNumEntry("TotalMsgs", -1);
00945 mCompactable = config->readBoolEntry("Compactable", true);
00946 if ( mSize == -1 )
00947 mSize = config->readNum64Entry("FolderSize", -1);
00948
00949 int type = config->readNumEntry( "ContentsType", 0 );
00950 if ( type < 0 || type > KMail::ContentsTypeLast ) type = 0;
00951 setContentsType( static_cast<KMail::FolderContentsType>( type ) );
00952
00953 if( folder() ) folder()->readConfig( config );
00954 }
00955
00956
00957 void FolderStorage::writeConfig()
00958 {
00959 KConfig* config = KMKernel::config();
00960 KConfigGroupSaver saver(config, "Folder-" + folder()->idString());
00961 config->writeEntry("UnreadMsgs",
00962 mGuessedUnreadMsgs == -1 ? mUnreadMsgs : mGuessedUnreadMsgs);
00963 config->writeEntry("TotalMsgs", mTotalMsgs);
00964 config->writeEntry("Compactable", mCompactable);
00965 config->writeEntry("ContentsType", mContentsType);
00966 config->writeEntry("FolderSize", mSize);
00967
00968
00969 if( folder() ) folder()->writeConfig( config );
00970
00971 GlobalSettings::self()->requestSync();
00972 }
00973
00974
00975 void FolderStorage::correctUnreadMsgsCount()
00976 {
00977 open("countunreadmsg");
00978 close("countunreadmsg");
00979 emit numUnreadMsgsChanged( folder() );
00980 }
00981
00982 void FolderStorage::registerWithMessageDict()
00983 {
00984 mExportsSernums = true;
00985 readFolderIdsFile();
00986 }
00987
00988 void FolderStorage::deregisterFromMessageDict()
00989 {
00990 writeFolderIdsFile();
00991 mExportsSernums = false;
00992 }
00993
00994 void FolderStorage::readFolderIdsFile()
00995 {
00996 if ( !mExportsSernums ) return;
00997 if ( KMMsgDict::mutableInstance()->readFolderIds( *this ) == -1 ) {
00998 invalidateFolder();
00999 }
01000 if ( !KMMsgDict::mutableInstance()->hasFolderIds( *this ) ) {
01001 invalidateFolder();
01002 }
01003 }
01004
01005 void FolderStorage::invalidateFolder()
01006 {
01007 if ( !mExportsSernums ) return;
01008 unlink(QFile::encodeName( indexLocation()) + ".sorted");
01009 unlink(QFile::encodeName( indexLocation()) + ".ids");
01010 fillMessageDict();
01011 KMMsgDict::mutableInstance()->writeFolderIds( *this );
01012 emit invalidated( folder() );
01013 }
01014
01015
01016
01017 int FolderStorage::writeFolderIdsFile() const
01018 {
01019 if ( !mExportsSernums ) return -1;
01020 return KMMsgDict::mutableInstance()->writeFolderIds( *this );
01021 }
01022
01023
01024 int FolderStorage::touchFolderIdsFile()
01025 {
01026 if ( !mExportsSernums ) return -1;
01027 return KMMsgDict::mutableInstance()->touchFolderIds( *this );
01028 }
01029
01030
01031 int FolderStorage::appendToFolderIdsFile( int idx )
01032 {
01033 if ( !mExportsSernums ) return -1;
01034 int ret = 0;
01035 if ( count() == 1 ) {
01036 ret = KMMsgDict::mutableInstance()->writeFolderIds( *this );
01037 } else {
01038 ret = KMMsgDict::mutableInstance()->appendToFolderIds( *this, idx );
01039 }
01040 return ret;
01041 }
01042
01043 void FolderStorage::replaceMsgSerNum( unsigned long sernum, KMMsgBase* msg, int idx )
01044 {
01045 if ( !mExportsSernums ) return;
01046 KMMsgDict::mutableInstance()->replace( sernum, msg, idx );
01047 }
01048
01049 void FolderStorage::setRDict( KMMsgDictREntry *rentry ) const
01050 {
01051 if ( ! mExportsSernums )
01052 kdDebug(5006) << "WTF, this FolderStorage should be invisible to the msgdict, who is calling us?" << kdBacktrace() << endl;
01053 assert( mExportsSernums );
01054 if ( rentry == mRDict )
01055 return;
01056 KMMsgDict::deleteRentry( mRDict );
01057 mRDict = rentry;
01058 }
01059
01060
01061 void FolderStorage::setStatus(int idx, KMMsgStatus status, bool toggle)
01062 {
01063 KMMsgBase *msg = getMsgBase(idx);
01064 if ( msg ) {
01065 if (toggle)
01066 msg->toggleStatus(status, idx);
01067 else
01068 msg->setStatus(status, idx);
01069 }
01070 }
01071
01072
01073
01074 void FolderStorage::setStatus(QValueList<int>& ids, KMMsgStatus status, bool toggle)
01075 {
01076 for ( QValueList<int>::Iterator it = ids.begin(); it != ids.end(); ++it )
01077 {
01078 FolderStorage::setStatus(*it, status, toggle);
01079 }
01080 }
01081
01082 void FolderStorage::ignoreJobsForMessage( KMMessage *msg )
01083 {
01084 if ( !msg || msg->transferInProgress() )
01085 return;
01086
01087 QPtrListIterator<FolderJob> it( mJobList );
01088 while ( it.current() )
01089 {
01090
01091
01092
01093 if ( it.current()->msgList().first() == msg )
01094 {
01095 FolderJob* job = it.current();
01096 mJobList.remove( job );
01097 delete job;
01098 } else
01099 ++it;
01100 }
01101 }
01102
01103
01104 void FolderStorage::removeJobs()
01105 {
01106 mJobList.setAutoDelete( true );
01107 mJobList.clear();
01108 mJobList.setAutoDelete( false );
01109 }
01110
01111
01112
01113
01114 void FolderStorage::updateChildrenState()
01115 {
01116 if ( folder() && folder()->child() )
01117 {
01118 if ( kmkernel->folderMgr()->folderCount( folder()->child() ) > 0 )
01119 setHasChildren( HasChildren );
01120 else
01121 setHasChildren( HasNoChildren );
01122 }
01123 }
01124
01125
01126 void FolderStorage::setNoChildren( bool aNoChildren )
01127 {
01128 mNoChildren = aNoChildren;
01129 if ( aNoChildren )
01130 setHasChildren( HasNoChildren );
01131 }
01132
01133
01134 void FolderStorage::setContentsType( KMail::FolderContentsType type, bool quiet )
01135 {
01136 if ( type != mContentsType ) {
01137 mContentsType = type;
01138 if ( !quiet )
01139 emit contentsTypeChanged( type );
01140 }
01141 }
01142
01143
01144 void FolderStorage::search( const KMSearchPattern* pattern )
01145 {
01146 mSearchPattern = pattern;
01147 mCurrentSearchedMsg = 0;
01148 if ( pattern )
01149 slotProcessNextSearchBatch();
01150 }
01151
01152 void FolderStorage::slotProcessNextSearchBatch()
01153 {
01154 if ( !mSearchPattern )
01155 return;
01156 QValueList<Q_UINT32> matchingSerNums;
01157 const int end = QMIN( mCurrentSearchedMsg + 15, count() );
01158 for ( int i = mCurrentSearchedMsg; i < end; ++i )
01159 {
01160 Q_UINT32 serNum = KMMsgDict::instance()->getMsgSerNum( folder(), i );
01161 if ( mSearchPattern->matches( serNum ) )
01162 matchingSerNums.append( serNum );
01163 }
01164 mCurrentSearchedMsg = end;
01165 bool complete = ( end >= count() );
01166 emit searchResult( folder(), matchingSerNums, mSearchPattern, complete );
01167 if ( !complete )
01168 QTimer::singleShot( 0, this, SLOT(slotProcessNextSearchBatch()) );
01169 }
01170
01171
01172 void FolderStorage::search( const KMSearchPattern* pattern, Q_UINT32 serNum )
01173 {
01174 bool matches = pattern && pattern->matches( serNum );
01175
01176 emit searchDone( folder(), serNum, pattern, matches );
01177 }
01178
01179
01180 int FolderStorage::addMsg( QPtrList<KMMessage>& msgList, QValueList<int>& index_ret )
01181 {
01182 int ret = 0;
01183 int index;
01184 for ( QPtrListIterator<KMMessage> it( msgList ); *it; ++it )
01185 {
01186 int aret = addMsg( *it, &index );
01187 index_ret << index;
01188 if ( aret != 0 )
01189 ret = aret;
01190 }
01191 return ret;
01192 }
01193
01194
01195 bool FolderStorage::isMoveable() const
01196 {
01197 return ( folder()->isSystemFolder() ) ? false : true;
01198 }
01199
01200
01201
01202 KMAccount* FolderStorage::account() const
01203 {
01204 return 0;
01205 }
01206
01207 bool FolderStorage::mailCheckInProgress() const
01208 {
01209 return false;
01210 }
01211
01212 bool FolderStorage::canDeleteMessages() const
01213 {
01214 return !isReadOnly();
01215 }
01216
01217 void FolderStorage::setNoContent(bool aNoContent)
01218 {
01219 const bool changed = aNoContent != mNoContent;
01220 mNoContent = aNoContent;
01221 if ( changed )
01222 emit noContentChanged();
01223 }
01224
01225 #include "folderstorage.moc"