00001
00002
00003
00004
00005 #include <config.h>
00006
00007 #include "kmfolder.h"
00008
00009 #include "kmfolderimap.h"
00010 #include "undostack.h"
00011 #include "kmmsgdict.h"
00012 #include "identitymanager.h"
00013 #include "kmidentity.h"
00014 #include "kmfoldermgr.h"
00015 #include "kmkernel.h"
00016 #include "kmcommands.h"
00017
00018 #include <kmessagebox.h>
00019 #include <klocale.h>
00020 #include <kconfig.h>
00021 #include <kdebug.h>
00022
00023 #include <qfile.h>
00024 #include <qregexp.h>
00025
00026 #include <mimelib/mimepp.h>
00027 #include <errno.h>
00028
00029
00030
00031 KMFolder :: KMFolder(KMFolderDir* aParent, const QString& aName) :
00032 KMFolderNode(aParent, aName)
00033 {
00034 mOpenCount = 0;
00035 mQuiet = 0;
00036 mChanged = FALSE;
00037 mAutoCreateIndex= TRUE;
00038 mIsSystemFolder = FALSE;
00039 mType = "plain";
00040 mAcctList = 0;
00041 mDirty = FALSE;
00042 mUnreadMsgs = -1;
00043 mGuessedUnreadMsgs = -1;
00044 mTotalMsgs = -1;
00045 needsCompact = FALSE;
00046 mChild = 0;
00047 mConvertToUtf8 = FALSE;
00048 mMailingListEnabled = FALSE;
00049 mCompactable = TRUE;
00050 mNoContent = FALSE;
00051 expireMessages = FALSE;
00052 unreadExpireAge = 28;
00053 unreadExpireUnits = expireNever;
00054 readExpireAge = 14;
00055 readExpireUnits = expireNever;
00056 mRDict = 0;
00057 mUseCustomIcons = false;
00058 mDirtyTimer = new QTimer(this);
00059 connect(mDirtyTimer, SIGNAL(timeout()),
00060 this, SLOT(updateIndex()));
00061
00062 if ( aParent ) {
00063 connect(this, SIGNAL(msgAdded(KMFolder*, Q_UINT32)),
00064 parent()->manager(), SIGNAL(msgAdded(KMFolder*, Q_UINT32)));
00065 connect(this, SIGNAL(msgRemoved(KMFolder*, Q_UINT32)),
00066 parent()->manager(), SIGNAL(msgRemoved(KMFolder*, Q_UINT32)));
00067 connect(this, SIGNAL(msgChanged(KMFolder*, Q_UINT32, int)),
00068 parent()->manager(), SIGNAL(msgChanged(KMFolder*, Q_UINT32, int)));
00069 connect(this, SIGNAL(msgHeaderChanged(KMFolder*, int)),
00070 parent()->manager(), SIGNAL(msgHeaderChanged(KMFolder*, int)));
00071 }
00072
00073 readConfig();
00074 }
00075
00076
00077
00078 KMFolder :: ~KMFolder()
00079 {
00080 delete mAcctList;
00081 mJobList.setAutoDelete( true );
00082 QObject::disconnect( SIGNAL(destroyed(QObject*)), this, 0 );
00083 mJobList.clear();
00084 KMMsgDict::deleteRentry(mRDict);
00085 }
00086
00087
00088
00089 QString KMFolder::dotEscape(const QString& aStr) const
00090 {
00091 if (aStr[0] != '.') return aStr;
00092 return aStr.left(aStr.find(QRegExp("[^\\.]"))) + aStr;
00093 }
00094
00095 void KMFolder::addJob( FolderJob* job ) const
00096 {
00097 QObject::connect( job, SIGNAL(destroyed(QObject*)),
00098 SLOT(removeJob(QObject*)) );
00099 mJobList.append( job );
00100 }
00101
00102 void KMFolder::removeJob( QObject* job )
00103 {
00104 mJobList.remove( static_cast<FolderJob*>( job ) );
00105 }
00106
00107
00108
00109 QString KMFolder::location() const
00110 {
00111 QString sLocation(path());
00112
00113 if (!sLocation.isEmpty()) sLocation += '/';
00114 sLocation += dotEscape(fileName());
00115
00116 return sLocation;
00117 }
00118
00119
00120
00121
00122 QString KMFolder::subdirLocation() const
00123 {
00124 QString sLocation(path());
00125
00126 if (!sLocation.isEmpty()) sLocation += '/';
00127 sLocation += '.';
00128 sLocation += dotEscape(fileName());
00129 sLocation += ".directory";
00130
00131 return sLocation;
00132 }
00133
00134
00135 KMFolderDir* KMFolder::createChildFolder()
00136 {
00137 QString childName = "." + fileName() + ".directory";
00138 QString childDir = path() + "/" + childName;
00139 bool ok = true;
00140
00141 if (mChild)
00142 return mChild;
00143
00144 if (access(QFile::encodeName(childDir), W_OK) != 0)
00145 {
00146 if (mkdir(QFile::encodeName(childDir), S_IRWXU) != 0
00147 && chmod(QFile::encodeName(childDir), S_IRWXU) != 0)
00148 ok=false;
00149 }
00150
00151 if (!ok) {
00152 QString wmsg = QString(" '%1': %2").arg(childDir).arg(strerror(errno));
00153 KMessageBox::information(0,i18n("Failed to create folder") + wmsg);
00154 return 0;
00155 }
00156
00157 KMFolderDir* folderDir = new KMFolderDir(parent(), childName,
00158 (folderType() == KMFolderTypeImap) ? KMImapDir : KMStandardDir);
00159 if (!folderDir)
00160 return 0;
00161 folderDir->reload();
00162 parent()->append(folderDir);
00163 mChild = folderDir;
00164 return folderDir;
00165 }
00166
00167
00168 void KMFolder::setAutoCreateIndex(bool autoIndex)
00169 {
00170 mAutoCreateIndex = autoIndex;
00171 }
00172
00173
00174 void KMFolder::setDirty(bool f)
00175 {
00176 mDirty = f;
00177 if (mDirty && mAutoCreateIndex)
00178 mDirtyTimer->changeInterval( mDirtyTimerInterval );
00179 else
00180 mDirtyTimer->stop();
00181 }
00182
00183
00184 void KMFolder::setIdentity( uint identity ) {
00185 mIdentity = identity;
00186 kmkernel->slotRequestConfigSync();
00187 }
00188
00189
00190 void KMFolder::markNewAsUnread()
00191 {
00192 KMMsgBase* msgBase;
00193 int i;
00194
00195 for (i=0; i< count(); ++i)
00196 {
00197 if (!(msgBase = getMsgBase(i))) continue;
00198 if (msgBase->isNew())
00199 {
00200 msgBase->setStatus(KMMsgStatusUnread);
00201 msgBase->setDirty(TRUE);
00202 }
00203 }
00204 }
00205
00206 void KMFolder::markUnreadAsRead()
00207 {
00208 KMMsgBase* msgBase;
00209 SerNumList serNums;
00210
00211 for (int i=count()-1; i>=0; --i)
00212 {
00213 msgBase = getMsgBase(i);
00214 assert(msgBase);
00215 if (msgBase->isNew() || msgBase->isUnread())
00216 {
00217 serNums.append( msgBase->getMsgSerNum() );
00218 }
00219 }
00220 if (serNums.empty())
00221 return;
00222
00223 KMCommand *command = new KMSetStatusCommand( KMMsgStatusRead, serNums );
00224 command->start();
00225 }
00226
00227
00228 void KMFolder::quiet(bool beQuiet)
00229 {
00230 if (beQuiet)
00231 mQuiet++;
00232 else {
00233 mQuiet--;
00234 if (mQuiet <= 0)
00235 {
00236 mQuiet = 0;
00237 if (mChanged)
00238 emit changed();
00239 mChanged = FALSE;
00240 }
00241 }
00242 }
00243
00244
00245
00246
00247
00249 int operator<( KMMsgBase & m1, KMMsgBase & m2 )
00250 {
00251 return (m1.date() < m2.date());
00252 }
00253
00255 int operator==( KMMsgBase & m1, KMMsgBase & m2 )
00256 {
00257 return (m1.date() == m2.date());
00258 }
00259
00260
00261
00262 int KMFolder::expungeOldMsg(int days)
00263 {
00264 int i, msgnb=0;
00265 time_t msgTime, maxTime;
00266 const KMMsgBase* mb;
00267 QValueList<int> rmvMsgList;
00268
00269 maxTime = time(0) - days * 3600 * 24;
00270
00271 for (i=count()-1; i>=0; i--) {
00272 mb = getMsgBase(i);
00273 assert(mb);
00274 msgTime = mb->date();
00275
00276 if (msgTime < maxTime) {
00277
00278 removeMsg( i );
00279 msgnb++;
00280 }
00281 }
00282 return msgnb;
00283 }
00284
00285
00286
00291 int
00292 KMFolder::daysToExpire(int number, ExpireUnits units) {
00293 switch (units) {
00294 case expireDays:
00295 return number;
00296 case expireWeeks:
00297 return number * 7;
00298 case expireMonths:
00299 return number * 31;
00300 default:
00301 ;
00302 }
00303
00304 return -1;
00305
00306 }
00307
00308
00314 void KMFolder::expireOldMessages() {
00315 FolderJob *job = createJob( 0, FolderJob::tExpireMessages );
00316 job->start();
00317 }
00318
00319
00320
00321 void KMFolder::emitMsgAddedSignals(int idx)
00322 {
00323 Q_UINT32 serNum = kmkernel->msgDict()->getMsgSerNum(this, idx);
00324 if (!mQuiet) {
00325 emit msgAdded(idx);
00326 } else {
00327 mChanged=true;
00328 }
00329 emit msgAdded(this, serNum);
00330 }
00331
00332
00333 bool KMFolder::canAddMsgNow(KMMessage* aMsg, int* aIndex_ret)
00334 {
00335 if (aIndex_ret) *aIndex_ret = -1;
00336 KMFolder *msgParent = aMsg->parent();
00337
00338
00339 if (aMsg->transferInProgress() && msgParent)
00340 return false;
00341 if (!aMsg->isComplete() && msgParent && msgParent->folderType() == KMFolderTypeImap)
00342 {
00343 FolderJob *job = msgParent->createJob(aMsg);
00344 connect(job, SIGNAL(messageRetrieved(KMMessage*)),
00345 SLOT(reallyAddMsg(KMMessage*)));
00346 job->start();
00347 aMsg->setTransferInProgress(TRUE);
00348 return FALSE;
00349 }
00350 return TRUE;
00351 }
00352
00353
00354
00355 void KMFolder::reallyAddMsg(KMMessage* aMsg)
00356 {
00357 if (!aMsg)
00358 return;
00359 aMsg->setTransferInProgress(FALSE);
00360 KMFolder *folder = aMsg->parent();
00361 int index;
00362 ulong serNum = aMsg->getMsgSerNum();
00363 bool undo = aMsg->enableUndo();
00364 addMsg(aMsg, &index);
00365 if (index < 0) return;
00366 unGetMsg(index);
00367 if (undo)
00368 {
00369 kmkernel->undoStack()->pushSingleAction( serNum, folder, this );
00370 }
00371 }
00372
00373
00374
00375 void KMFolder::reallyAddCopyOfMsg(KMMessage* aMsg)
00376 {
00377 aMsg->setParent( 0 );
00378 aMsg->setTransferInProgress( false );
00379 addMsg( aMsg );
00380 unGetMsg( count() - 1 );
00381 }
00382
00383 int KMFolder::find( const KMMessage * msg ) const {
00384 return find( &msg->toMsgBase() );
00385 }
00386
00387
00388 void KMFolder::removeMsg(QPtrList<KMMessage> msgList, bool imapQuiet)
00389 {
00390 for ( KMMessage* msg = msgList.first(); msg; msg = msgList.next() )
00391 {
00392 int idx = find(msg);
00393 assert( idx != -1);
00394 removeMsg(idx, imapQuiet);
00395 }
00396 }
00397
00398
00399 void KMFolder::removeMsg(int idx, bool)
00400 {
00401
00402 if(idx < 0)
00403 {
00404 kdDebug(5006) << "KMFolder::removeMsg() : idx < 0\n" << endl;
00405 return;
00406 }
00407
00408 KMMsgBase* mb = getMsgBase(idx);
00409
00410 Q_UINT32 serNum = kmkernel->msgDict()->getMsgSerNum(this, idx);
00411 if (serNum != 0)
00412 emit msgRemoved(this, serNum);
00413 mb = takeIndexEntry( idx );
00414
00415 setDirty( true );
00416 needsCompact=true;
00417
00418 if (mb->isUnread() || mb->isNew() ||
00419 (this == kmkernel->outboxFolder())) {
00420 --mUnreadMsgs;
00421 emit numUnreadMsgsChanged( this );
00422 }
00423 --mTotalMsgs;
00424
00425 QString msgIdMD5 = mb->msgIdMD5();
00426 QString strippedSubjMD5 = mb->strippedSubjectMD5();
00427 if (strippedSubjMD5.isEmpty()) {
00428 mb->initStrippedSubjectMD5();
00429 strippedSubjMD5 = mb->strippedSubjectMD5();
00430 }
00431 emit msgRemoved(idx, msgIdMD5, strippedSubjMD5);
00432 emit msgRemoved(this);
00433 }
00434
00435
00436
00437 KMMessage* KMFolder::take(int idx)
00438 {
00439 KMMsgBase* mb;
00440 KMMessage* msg;
00441
00442 assert(idx>=0 && idx<=count());
00443
00444 mb = getMsgBase(idx);
00445 if (!mb) return 0;
00446 if (!mb->isMessage()) readMsg(idx);
00447 Q_UINT32 serNum = kmkernel->msgDict()->getMsgSerNum(this, idx);
00448 emit msgRemoved(this,serNum);
00449
00450 msg = (KMMessage*)takeIndexEntry(idx);
00451
00452 if (msg->isUnread() || msg->isNew() ||
00453 (this == kmkernel->outboxFolder())) {
00454 --mUnreadMsgs;
00455 emit numUnreadMsgsChanged( this );
00456 }
00457 --mTotalMsgs;
00458 msg->setParent(0);
00459 setDirty( true );
00460 needsCompact=true;
00461 QString msgIdMD5 = msg->msgIdMD5();
00462 QString strippedSubjMD5 = msg->strippedSubjectMD5();
00463 if (strippedSubjMD5.isEmpty()) {
00464 msg->initStrippedSubjectMD5();
00465 strippedSubjMD5 = msg->strippedSubjectMD5();
00466 }
00467 emit msgRemoved(idx, msgIdMD5, strippedSubjMD5);
00468 emit msgRemoved(this);
00469
00470 return msg;
00471 }
00472
00473 void KMFolder::take(QPtrList<KMMessage> msgList)
00474 {
00475 for ( KMMessage* msg = msgList.first(); msg; msg = msgList.next() )
00476 {
00477 if (msg->parent())
00478 {
00479 int idx = msg->parent()->find(msg);
00480 assert( idx != -1);
00481 KMFolder::take(idx);
00482 }
00483 }
00484 }
00485
00486
00487
00488 KMMessage* KMFolder::getMsg(int idx)
00489 {
00490 KMMsgBase* mb;
00491
00492 if(!(idx >= 0 && idx <= count()))
00493 return 0;
00494
00495 mb = getMsgBase(idx);
00496 if (!mb) return 0;
00497
00498 #if 0
00499 if (mb->isMessage()) return ((KMMessage*)mb);
00500 return readMsg(idx);
00501 #else
00502 KMMessage *msg = 0;
00503 bool undo = mb->enableUndo();
00504 if (mb->isMessage()) {
00505 msg = ((KMMessage*)mb);
00506 } else {
00507 QString mbSubject = mb->subject();
00508 msg = readMsg(idx);
00509
00510 if (mCompactable && (!msg || (msg->subject().isEmpty() != mbSubject.isEmpty()))) {
00511 kdDebug(5006) << "Error: " << location() <<
00512 " Index file is inconsistent with folder file. This should never happen." << endl;
00513 mCompactable = FALSE;
00514 writeConfig();
00515 }
00516 }
00517 msg->setEnableUndo(undo);
00518
00519 if (msg->getMsgSerNum() == 0) {
00520 msg->setMsgSerNum(kmkernel->msgDict()->insert(0, msg, idx));
00521 kdDebug(5006) << "Serial number generated for message in folder " << label() << endl;
00522 }
00523 msg->setComplete( true );
00524 return msg;
00525 #endif
00526
00527
00528 }
00529
00530
00531
00532 KMMsgInfo* KMFolder::unGetMsg(int idx)
00533 {
00534 KMMsgBase* mb;
00535
00536 if(!(idx >= 0 && idx <= count()))
00537 return 0;
00538
00539 mb = getMsgBase(idx);
00540 if (!mb) return 0;
00541
00542
00543 if (mb->isMessage()) {
00544
00545
00546 KMMessage *msg = static_cast<KMMessage*>(mb);
00547 if ( msg->transferInProgress() ) return 0;
00548 ignoreJobsForMessage( msg );
00549 return setIndexEntry( idx, msg );
00550 }
00551
00552 return 0;
00553 }
00554
00555
00556
00557 bool KMFolder::isMessage(int idx)
00558 {
00559 KMMsgBase* mb;
00560 if (!(idx >= 0 && idx <= count())) return FALSE;
00561 mb = getMsgBase(idx);
00562 return (mb && mb->isMessage());
00563 }
00564
00565
00566 FolderJob* KMFolder::createJob( KMMessage *msg, FolderJob::JobType jt,
00567 KMFolder *folder, QString partSpecifier,
00568 const AttachmentStrategy *as ) const
00569 {
00570 FolderJob * job = doCreateJob( msg, jt, folder, partSpecifier, as );
00571 if ( job )
00572 addJob( job );
00573 return job;
00574 }
00575
00576
00577 FolderJob* KMFolder::createJob( QPtrList<KMMessage>& msgList, const QString& sets,
00578 FolderJob::JobType jt, KMFolder *folder ) const
00579 {
00580 FolderJob * job = doCreateJob( msgList, sets, jt, folder );
00581 if ( job )
00582 addJob( job );
00583 return job;
00584 }
00585
00586
00587 int KMFolder::moveMsg(KMMessage* aMsg, int* aIndex_ret)
00588 {
00589 KMFolder* msgParent;
00590 int rc;
00591
00592 assert(aMsg != 0);
00593 msgParent = aMsg->parent();
00594
00595 if (msgParent)
00596 msgParent->open();
00597
00598 open();
00599 rc = addMsg(aMsg, aIndex_ret);
00600 close();
00601
00602 if (msgParent)
00603 msgParent->close();
00604
00605 return rc;
00606 }
00607
00608
00609 int KMFolder::moveMsg(QPtrList<KMMessage> msglist, int* aIndex_ret)
00610 {
00611 KMFolder* msgParent;
00612 int rc;
00613
00614 KMMessage* aMsg = msglist.first();
00615 assert(aMsg != 0);
00616 msgParent = aMsg->parent();
00617
00618 if (msgParent)
00619 msgParent->open();
00620
00621 open();
00622
00623 rc = static_cast<KMFolderImap*>(this)->addMsg(msglist, aIndex_ret);
00624 close();
00625
00626 if (msgParent)
00627 msgParent->close();
00628
00629 return rc;
00630 }
00631
00632
00633
00634 int KMFolder::rename(const QString& newName, KMFolderDir *newParent)
00635 {
00636 QString oldLoc, oldIndexLoc, oldIdsLoc, newLoc, newIndexLoc, newIdsLoc;
00637 QString oldSubDirLoc, newSubDirLoc;
00638 QString oldName;
00639 int rc=0, openCount=mOpenCount;
00640 KMFolderDir *oldParent;
00641
00642 assert(!newName.isEmpty());
00643
00644 oldLoc = location();
00645 oldIndexLoc = indexLocation();
00646 oldSubDirLoc = subdirLocation();
00647 if (kmkernel->msgDict())
00648 oldIdsLoc = kmkernel->msgDict()->getFolderIdsLocation(this);
00649
00650 close(TRUE);
00651
00652 oldName = fileName();
00653 oldParent = parent();
00654 if (newParent)
00655 setParent( newParent );
00656
00657 setName(newName);
00658 newLoc = location();
00659 newIndexLoc = indexLocation();
00660 newSubDirLoc = subdirLocation();
00661 if (kmkernel->msgDict())
00662 newIdsLoc = kmkernel->msgDict()->getFolderIdsLocation(this);
00663
00664 if (::rename(QFile::encodeName(oldLoc), QFile::encodeName(newLoc))) {
00665 setName(oldName);
00666 setParent(oldParent);
00667 rc = errno;
00668 }
00669 else {
00670
00671 if (!oldIndexLoc.isEmpty()) {
00672 ::rename(QFile::encodeName(oldIndexLoc), QFile::encodeName(newIndexLoc));
00673 ::rename(QFile::encodeName(oldIndexLoc) + ".sorted",
00674 QFile::encodeName(newIndexLoc) + ".sorted");
00675 }
00676
00677
00678 if (!oldIdsLoc.isEmpty())
00679 ::rename(QFile::encodeName(oldIdsLoc), QFile::encodeName(newIdsLoc));
00680
00681
00682 if (!::rename(QFile::encodeName(oldSubDirLoc), QFile::encodeName(newSubDirLoc) )) {
00683
00684
00685
00686 if( mChild && ( oldName != newName ) ) {
00687 mChild->setName( "." + QFile::encodeName(newName) + ".directory" );
00688 }
00689 }
00690
00691
00692
00693 if (newParent) {
00694 if (oldParent->findRef( this ) != -1)
00695 oldParent->take();
00696 newParent->inSort( this );
00697 if (mChild) {
00698 if (mChild->parent()->findRef( mChild ) != -1)
00699 mChild->parent()->take();
00700 newParent->inSort( mChild );
00701 mChild->setParent( newParent );
00702 }
00703 }
00704 }
00705
00706 if (openCount > 0)
00707 {
00708 open();
00709 mOpenCount = openCount;
00710 }
00711
00712 emit nameChanged();
00713 return rc;
00714 }
00715
00716
00717
00718 int KMFolder::remove()
00719 {
00720 assert(!name().isEmpty());
00721
00722 mChild = 0;
00723 clearIndex(true, true);
00724 close(TRUE);
00725
00726 if (kmkernel->msgDict()) kmkernel->msgDict()->removeFolderIds(this);
00727 unlink(QFile::encodeName(indexLocation()) + ".sorted");
00728 unlink(QFile::encodeName(indexLocation()));
00729
00730 int rc = removeContents();
00731 if (rc) return rc;
00732
00733 needsCompact = false;
00734 return 0;
00735 }
00736
00737
00738
00739 int KMFolder::expunge()
00740 {
00741 int openCount = mOpenCount;
00742
00743 assert(!name().isEmpty());
00744
00745 clearIndex(true, true);
00746 close(TRUE);
00747
00748 kmkernel->msgDict()->removeFolderIds(this);
00749 if (mAutoCreateIndex)
00750 truncateIndex();
00751 else unlink(QFile::encodeName(indexLocation()));
00752
00753 int rc = expungeContents();
00754 if (rc) return rc;
00755
00756 mDirty = FALSE;
00757 needsCompact = false;
00758
00759 if (openCount > 0)
00760 {
00761 open();
00762 mOpenCount = openCount;
00763 }
00764
00765 mUnreadMsgs = 0;
00766 mTotalMsgs = 0;
00767 emit numUnreadMsgsChanged( this );
00768 if (mAutoCreateIndex)
00769 writeConfig();
00770 emit changed();
00771 emit expunged();
00772
00773 return 0;
00774 }
00775
00776
00777
00778 const char* KMFolder::type() const
00779 {
00780 if (mAcctList) return "In";
00781 return KMFolderNode::type();
00782 }
00783
00784
00785
00786 QString KMFolder::label() const
00787 {
00788 if (mIsSystemFolder && !mLabel.isEmpty()) return mLabel;
00789 if (mIsSystemFolder) return i18n(name().latin1());
00790 return name();
00791 }
00792
00793 int KMFolder::count(bool cache) const
00794 {
00795 if (cache && mTotalMsgs != -1)
00796 return mTotalMsgs;
00797 else
00798 return -1;
00799 }
00800
00801
00802 int KMFolder::countUnread()
00803 {
00804 if (mGuessedUnreadMsgs > -1)
00805 return mGuessedUnreadMsgs;
00806 if (mUnreadMsgs > -1)
00807 return mUnreadMsgs;
00808
00809 readConfig();
00810
00811 if (mUnreadMsgs > -1)
00812 return mUnreadMsgs;
00813
00814 open();
00815 int unread = mUnreadMsgs;
00816 close();
00817 return (unread > 0) ? unread : 0;
00818 }
00819
00820
00821 int KMFolder::countUnreadRecursive()
00822 {
00823 KMFolder *folder;
00824 int count = countUnread();
00825 KMFolderDir *dir = child();
00826 if (!dir)
00827 return count;
00828
00829 QPtrListIterator<KMFolderNode> it(*dir);
00830 for ( ; it.current(); ++it )
00831 if (!it.current()->isDir()) {
00832 folder = static_cast<KMFolder*>(it.current());
00833 count += folder->countUnreadRecursive();
00834 }
00835
00836 return count;
00837 }
00838
00839
00840 void KMFolder::msgStatusChanged(const KMMsgStatus oldStatus,
00841 const KMMsgStatus newStatus, int idx)
00842 {
00843 int oldUnread = 0;
00844 int newUnread = 0;
00845
00846 if (oldStatus & KMMsgStatusUnread || oldStatus & KMMsgStatusNew ||
00847 (this == kmkernel->outboxFolder()))
00848 oldUnread = 1;
00849 if (newStatus & KMMsgStatusUnread || newStatus & KMMsgStatusNew ||
00850 (this == kmkernel->outboxFolder()))
00851 newUnread = 1;
00852 int deltaUnread = newUnread - oldUnread;
00853
00854 mDirtyTimer->changeInterval(mDirtyTimerInterval);
00855 if (deltaUnread != 0) {
00856 if (mUnreadMsgs < 0) mUnreadMsgs = 0;
00857 mUnreadMsgs += deltaUnread;
00858 emit numUnreadMsgsChanged( this );
00859
00860 Q_UINT32 serNum = kmkernel->msgDict()->getMsgSerNum(this, idx);
00861 emit msgChanged( this, serNum, deltaUnread );
00862 }
00863 }
00864
00865
00866 void KMFolder::headerOfMsgChanged(const KMMsgBase* aMsg, int idx)
00867 {
00868 if (idx < 0)
00869 idx = aMsg->parent()->find( aMsg );
00870 if (idx >= 0 && !mQuiet)
00871 emit msgHeaderChanged(this, idx);
00872 else
00873 mChanged = TRUE;
00874 }
00875
00876
00877 QString KMFolder::idString() const
00878 {
00879 KMFolderNode* folderNode = parent();
00880 if (!folderNode)
00881 return "";
00882 while (folderNode->parent())
00883 folderNode = folderNode->parent();
00884 int pathLen = path().length() - folderNode->path().length();
00885 QString relativePath = path().right( pathLen );
00886 if (!relativePath.isEmpty())
00887 relativePath = relativePath.right( relativePath.length() - 1 ) + "/";
00888 QString escapedName = QString( name() );
00889
00890
00891 escapedName.replace( "[", "%(" );
00892 escapedName.replace( "]", "%)" );
00893 return relativePath + escapedName;
00894 }
00895
00896
00897 void KMFolder::readConfig()
00898 {
00899
00900 KConfig* config = KMKernel::config();
00901 KConfigGroupSaver saver(config, "Folder-" + idString());
00902 if (mUnreadMsgs == -1)
00903 mUnreadMsgs = config->readNumEntry("UnreadMsgs", -1);
00904 if (mTotalMsgs == -1)
00905 mTotalMsgs = config->readNumEntry("TotalMsgs", -1);
00906 mMailingListEnabled = config->readBoolEntry("MailingListEnabled");
00907 mMailingListPostingAddress = config->readEntry("MailingListPostingAddress");
00908 mMailingListAdminAddress = config->readEntry("MailingListAdminAddress");
00909 mIdentity = config->readUnsignedNumEntry("Identity",0);
00910 mCompactable = config->readBoolEntry("Compactable", TRUE);
00911
00912 expireMessages = config->readBoolEntry("ExpireMessages", FALSE);
00913 readExpireAge = config->readNumEntry("ReadExpireAge", 3);
00914 readExpireUnits = (ExpireUnits)config->readNumEntry("ReadExpireUnits", expireMonths);
00915 unreadExpireAge = config->readNumEntry("UnreadExpireAge", 12);
00916 unreadExpireUnits = (ExpireUnits)config->readNumEntry("UnreadExpireUnits", expireNever);
00917 setUserWhoField( config->readEntry("WhoField"), false );
00918 mUseCustomIcons = config->readBoolEntry("UseCustomIcons", false );
00919 mNormalIconPath = config->readEntry("NormalIconPath" );
00920 mUnreadIconPath = config->readEntry("UnreadIconPath" );
00921 if ( mUseCustomIcons )
00922 emit iconsChanged();
00923 }
00924
00925
00926 void KMFolder::writeConfig()
00927 {
00928 KConfig* config = KMKernel::config();
00929 KConfigGroupSaver saver(config, "Folder-" + idString());
00930 config->writeEntry("UnreadMsgs", countUnread());
00931 config->writeEntry("TotalMsgs", mTotalMsgs);
00932 config->writeEntry("MailingListEnabled", mMailingListEnabled);
00933 config->writeEntry("MailingListPostingAddress", mMailingListPostingAddress);
00934 config->writeEntry("MailingListAdminAddress", mMailingListAdminAddress);
00935 config->writeEntry("Identity", mIdentity);
00936 config->writeEntry("Compactable", mCompactable);
00937 config->writeEntry("ExpireMessages", expireMessages);
00938 config->writeEntry("ReadExpireAge", readExpireAge);
00939 config->writeEntry("ReadExpireUnits", readExpireUnits);
00940 config->writeEntry("UnreadExpireAge", unreadExpireAge);
00941 config->writeEntry("UnreadExpireUnits", unreadExpireUnits);
00942 config->writeEntry("WhoField", mUserWhoField);
00943
00944 config->writeEntry("UseCustomIcons", mUseCustomIcons);
00945 config->writeEntry("NormalIconPath", mNormalIconPath);
00946 config->writeEntry("UnreadIconPath", mUnreadIconPath);
00947 }
00948
00949
00950 void KMFolder::correctUnreadMsgsCount()
00951 {
00952 open();
00953 close();
00954 emit numUnreadMsgsChanged( this );
00955 }
00956
00957
00958 void KMFolder::fillMsgDict(KMMsgDict *dict)
00959 {
00960 fillDictFromIndex(dict);
00961 }
00962
00963
00964 int KMFolder::writeMsgDict(KMMsgDict *dict)
00965 {
00966 int ret = 0;
00967 if (!dict)
00968 dict = kmkernel->msgDict();
00969 if (dict)
00970 ret = dict->writeFolderIds(this);
00971 return ret;
00972 }
00973
00974
00975 int KMFolder::touchMsgDict()
00976 {
00977 int ret = 0;
00978 KMMsgDict *dict = kmkernel->msgDict();
00979 if (dict)
00980 ret = dict->touchFolderIds(this);
00981 return ret;
00982 }
00983
00984
00985 int KMFolder::appendtoMsgDict(int idx)
00986 {
00987 int ret = 0;
00988 KMMsgDict *dict = kmkernel->msgDict();
00989 if (dict) {
00990 if (count() == 1) {
00991 ret = dict->writeFolderIds(this);
00992 } else {
00993 ret = dict->appendtoFolderIds(this, idx);
00994 }
00995 }
00996 return ret;
00997 }
00998
00999
01000 void KMFolder::setStatus(int idx, KMMsgStatus status, bool toggle)
01001 {
01002 KMMsgBase *msg = getMsgBase(idx);
01003 if ( msg ) {
01004 if (toggle)
01005 msg->toggleStatus(status, idx);
01006 else
01007 msg->setStatus(status, idx);
01008 }
01009 }
01010
01011 void KMFolder::setRDict(KMMsgDictREntry *rentry) {
01012 if (rentry == mRDict)
01013 return;
01014 KMMsgDict::deleteRentry(mRDict);
01015 mRDict = rentry;
01016 }
01017
01018
01019 void KMFolder::setStatus(QValueList<int>& ids, KMMsgStatus status, bool toggle)
01020 {
01021 for ( QValueList<int>::Iterator it = ids.begin(); it != ids.end(); ++it )
01022 {
01023 KMFolder::setStatus(*it, status, toggle);
01024 }
01025 }
01026
01027
01028 void KMFolder::setUserWhoField(const QString &whoField, bool aWriteConfig)
01029 {
01030 mUserWhoField = whoField;
01031 if ( whoField.isEmpty() )
01032 {
01033
01034 const KMIdentity & identity =
01035 kmkernel->identityManager()->identityForUoidOrDefault( mIdentity );
01036
01037 if ( mIsSystemFolder && folderType() != KMFolderTypeImap )
01038 {
01039
01040 if ( this == kmkernel->inboxFolder() || this == kmkernel->trashFolder() ) mWhoField = "From";
01041 if ( this == kmkernel->outboxFolder() || this == kmkernel->sentFolder() || this == kmkernel->draftsFolder() ) mWhoField = "To";
01042
01043 } else if ( identity.drafts() == idString() || identity.fcc() == idString() ) {
01044
01045 mWhoField = "To";
01046 } else {
01047 mWhoField = "From";
01048 }
01049
01050 } else if ( whoField == "From" || whoField == "To" ) {
01051
01052
01053 mWhoField = whoField;
01054
01055 } else {
01056
01057 kdDebug(5006) << "Illegal setting " << whoField << " for userWhoField!" << endl;
01058 }
01059
01060 if (aWriteConfig)
01061 writeConfig();
01062 }
01063
01064 void KMFolder::ignoreJobsForMessage( KMMessage *msg )
01065 {
01066 if ( !msg || msg->transferInProgress() )
01067 return;
01068
01069 QPtrListIterator<FolderJob> it( mJobList );
01070 while ( it.current() )
01071 {
01072
01073
01074
01075 if ( it.current()->msgList().first() == msg )
01076 {
01077 FolderJob* job = it.current();
01078 mJobList.remove( job );
01079 delete job;
01080 } else
01081 ++it;
01082 }
01083 }
01084
01085 void KMFolder::setIconPaths(const QString &normalPath, const QString &unreadPath)
01086 {
01087 mNormalIconPath = normalPath;
01088 mUnreadIconPath = unreadPath;
01089 writeConfig();
01090 emit iconsChanged();
01091 }
01092
01093
01094 void KMFolder::removeJobs()
01095 {
01096 mJobList.setAutoDelete( true );
01097 mJobList.clear();
01098 mJobList.setAutoDelete( false );
01099 }
01100
01101
01102 size_t KMFolder::crlf2lf( char* str, const size_t strLen )
01103 {
01104 if ( !str || strLen == 0 ) return 0;
01105
01106 const char* source = str;
01107 const char* sourceEnd = source + strLen;
01108
01109
01110 for ( ; source < sourceEnd - 1; ++source ) {
01111 if ( *source == '\r' && *( source + 1 ) == '\n' )
01112 break;
01113 }
01114
01115 if ( source == sourceEnd - 1 ) {
01116
01117 return strLen;
01118 }
01119
01120
01121 char* target = const_cast<char*>( source );
01122 ++source;
01123 for ( ; source < sourceEnd; ++source ) {
01124 if ( *source != '\r' || *( source + 1 ) != '\n' )
01125 *target++ = *source;
01126 }
01127 *target = '\0';
01128 return target - str;
01129 }
01130
01131 #include "kmfolder.moc"