kmail Library API Documentation

kmfolder.cpp

00001 // -*- mode: C++; c-file-style: "gnu" -*- 00002 // kmfolder.cpp 00003 // Author: Stefan Taferner <taferner@alpin.or.at> 00004 00005 #include <config.h> 00006 00007 #include "kmfolder.h" 00008 00009 #include "kmfolderimap.h" //for the nasty imap hacks, FIXME 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 //FIXME: Centralize all the readConfig calls somehow - Zack 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) // Not there or not writable 00145 { 00146 if (mkdir(QFile::encodeName(childDir), S_IRWXU) != 0 00147 && chmod(QFile::encodeName(childDir), S_IRWXU) != 0) 00148 ok=false; //failed create new or chmod existing tmp/ 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 // Needed to use QSortedList in reduceSize() 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 //kdDebug(5006) << "deleting msg " << i << " : " << mb->subject() << " - " << mb->dateStr(); // << endl; 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: // Days 00295 return number; 00296 case expireWeeks: // Weeks 00297 return number * 7; 00298 case expireMonths: // Months - this could be better rather than assuming 31day months. 00299 return number * 31; 00300 default: // this avoids a compiler warning (not handled enumeration values) 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 // If the message has a parent and is in transfer, bail out. If it does not 00338 // have a parent we want to be able to add it even if it is in transfer. 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) // the signal that is connected can call with aMsg=0 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 //assert(idx>=0); 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; // message is taken from here - needs to be compacted 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; // message is taken from here - needs to be compacted 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 // sanity check 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; // Don't compact 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 // Remove this message from all jobs' list it might still be on. 00545 // setIndexEntry deletes the message. 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 //FIXME : is it always imap ? 00623 rc = static_cast<KMFolderImap*>(this)->addMsg(msglist, aIndex_ret); //yuck: Don 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 // rename/move index file and index.sorted file 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 // rename/move serial number file 00678 if (!oldIdsLoc.isEmpty()) 00679 ::rename(QFile::encodeName(oldIdsLoc), QFile::encodeName(newIdsLoc)); 00680 00681 // rename/move the subfolder directory 00682 if (!::rename(QFile::encodeName(oldSubDirLoc), QFile::encodeName(newSubDirLoc) )) { 00683 // now that the subfolder directory has been renamed and/or moved also 00684 // change the name that is stored in the corresponding KMFolderNode 00685 // (provide that the name actually changed) 00686 if( mChild && ( oldName != newName ) ) { 00687 mChild->setName( "." + QFile::encodeName(newName) + ".directory" ); 00688 } 00689 } 00690 00691 // if the folder is being moved then move its node and, if necessary, also 00692 // the associated subfolder directory node to the new parent 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); // delete and remove from dict 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; //we are dead - no need to compact us 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); // delete and remove from dict 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; //we're cleared and truncated no need to compact 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(); // will update unreadMsgs 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 /* Escape [ and ] as they are disallowed for kconfig sections and that is 00890 what the idString is primarily used for. */ 00891 escapedName.replace( "[", "%(" ); 00892 escapedName.replace( "]", "%)" ); 00893 return relativePath + escapedName; 00894 } 00895 00896 //----------------------------------------------------------------------------- 00897 void KMFolder::readConfig() 00898 { 00899 //kdDebug(5006)<<"#### READING CONFIG = "<< name() <<endl; 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 // default setting 01034 const KMIdentity & identity = 01035 kmkernel->identityManager()->identityForUoidOrDefault( mIdentity ); 01036 01037 if ( mIsSystemFolder && folderType() != KMFolderTypeImap ) 01038 { 01039 // local system folders 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 // drafts or sent of the identity 01045 mWhoField = "To"; 01046 } else { 01047 mWhoField = "From"; 01048 } 01049 01050 } else if ( whoField == "From" || whoField == "To" ) { 01051 01052 // set the whoField according to the user-setting 01053 mWhoField = whoField; 01054 01055 } else { 01056 // this should not happen... 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 //FIXME: the questions is : should we iterate through all 01073 //messages in jobs? I don't think so, because it would 01074 //mean canceling the jobs that work with other messages 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 // search the first occurrence of "\r\n" 01110 for ( ; source < sourceEnd - 1; ++source ) { 01111 if ( *source == '\r' && *( source + 1 ) == '\n' ) 01112 break; 01113 } 01114 01115 if ( source == sourceEnd - 1 ) { 01116 // no "\r\n" found 01117 return strLen; 01118 } 01119 01120 // replace all occurrences of "\r\n" with "\n" (in place) 01121 char* target = const_cast<char*>( source ); // target points to '\r' 01122 ++source; // source points to '\n' 01123 for ( ; source < sourceEnd; ++source ) { 01124 if ( *source != '\r' || *( source + 1 ) != '\n' ) 01125 *target++ = *source; 01126 } 01127 *target = '\0'; // terminate result 01128 return target - str; 01129 } 01130 01131 #include "kmfolder.moc"
KDE Logo
This file is part of the documentation for kmail Library Version 3.2.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Jul 28 23:58:00 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003