folderstorage.cpp
00001 /* 00002 Virtual base class for mail storage. 00003 00004 This file is part of KMail. 00005 00006 Copyright (c) 2004 Bo Thorsen <bo@sonofthor.dk> 00007 00008 This library is free software; you can redistribute it and/or 00009 modify it under the terms of the GNU Library General Public 00010 License as published by the Free Software Foundation; either 00011 version 2 of the License, or (at your option) any later version. 00012 00013 This library is distributed in the hope that it will be useful, 00014 but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 Library General Public License for more details. 00017 00018 You should have received a copy of the GNU Library General Public License 00019 along with this library; see the file COPYING.LIB. If not, write to 00020 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00021 Boston, MA 02110-1301, USA. 00022 00023 In addition, as a special exception, the copyright holders give 00024 permission to link the code of this program with any edition of 00025 the TQt library by Trolltech AS, Norway (or with modified versions 00026 of TQt that use the same license as TQt), and distribute linked 00027 combinations including the two. You must obey the GNU General 00028 Public License in all respects for all of the code used other than 00029 TQt. If you modify this file, you may extend this exception to 00030 your version of the file, but you are not obligated to do so. If 00031 you do not wish to do so, delete this exception statement from 00032 your version. 00033 */ 00034 00035 #include <config.h> 00036 00037 #include "folderstorage.h" 00038 #include "kmfolder.h" 00039 #include "kmkernel.h" 00040 00041 #include "kmfolderimap.h" //for the nasty imap hacks, FIXME 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 <tqfile.h> 00056 #include <tqregexp.h> 00057 00058 #include <mimelib/mimepp.h> 00059 #include <errno.h> 00060 00061 //----------------------------------------------------------------------------- 00062 00063 FolderStorage::FolderStorage( KMFolder* folder, const char* aName ) 00064 : TQObject( 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 TQTimer(this, "mDirtyTimer"); 00083 connect(mDirtyTimer, TQT_SIGNAL(timeout()), 00084 this, TQT_SLOT(updateIndex())); 00085 00086 mHasChildren = HasNoChildren; 00087 mContentsType = KMail::ContentsTypeMail; 00088 00089 connect(this, TQT_SIGNAL(closed(KMFolder*)), mFolder, TQT_SIGNAL(closed())); 00090 } 00091 00092 //----------------------------------------------------------------------------- 00093 FolderStorage::~FolderStorage() 00094 { 00095 mJobList.setAutoDelete( true ); 00096 TQObject::disconnect( TQT_SIGNAL(destroyed(TQObject*)), 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 // kdWarning() << "Really closing: " << folder()->prettyURL() << kdBacktrace() << endl; 00109 reallyDoClose(owner); 00110 } 00111 00112 //----------------------------------------------------------------------------- 00113 TQString FolderStorage::dotEscape(const TQString& aStr) 00114 { 00115 if (aStr[0] != '.') return aStr; 00116 return aStr.left(aStr.find(TQRegExp("[^\\.]"))) + aStr; 00117 } 00118 00119 void FolderStorage::addJob( FolderJob* job ) const 00120 { 00121 TQObject::connect( job, TQT_SIGNAL(destroyed(TQObject*)), 00122 TQT_SLOT(removeJob(TQObject*)) ); 00123 mJobList.append( job ); 00124 } 00125 00126 void FolderStorage::removeJob( TQObject* job ) 00127 { 00128 mJobList.remove( static_cast<FolderJob*>( job ) ); 00129 } 00130 00131 00132 //----------------------------------------------------------------------------- 00133 TQString FolderStorage::location() const 00134 { 00135 TQString sLocation(const_cast<FolderStorage*>(this)->folder()->path()); 00136 00137 if (!sLocation.isEmpty()) sLocation += '/'; 00138 sLocation += dotEscape(fileName()); 00139 00140 return sLocation; 00141 } 00142 00143 TQString 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 KMSeStatusCommand( KMMsgStatusRead, serNums ); 00201 command->start(); 00202 } 00203 00204 //----------------------------------------------------------------------------- 00205 void FolderStorage::quiet(bool beQuiet) 00206 { 00207 00208 if (beQuiet) 00209 { 00210 /* Allocate the timer here to don't have one timer for each folder. BTW, 00211 * a timer is created when a folder is checked 00212 */ 00213 if ( !mEmitChangedTimer) { 00214 mEmitChangedTimer= new TQTimer( this, "mEmitChangedTimer" ); 00215 connect( mEmitChangedTimer, TQT_SIGNAL( timeout() ), 00216 this, TQT_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 // Don't hurt emit this if the mUnreadMsg really don't change 00230 // We emit it here, because this signal is delayed if mQuiet >0 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 TQValueList<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 //kdDebug(5006) << "deleting msg " << i << " : " << mb->subject() << " - " << mb->dateStr(); // << endl; 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 TQ_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 // If the message has a parent and is in transfer, bail out. If it does not 00306 // have a parent we want to be able to add it even if it is in transfer. 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, TQT_SIGNAL(messageRetrieved(KMMessage*)), 00313 TQT_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) // the signal that is connected can call with aMsg=0 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; // messageRetrieved(0) is always possible 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 TQPtrList<KMMsgBase>& msgList, bool imapQuiet) 00359 { 00360 for( TQPtrListIterator<KMMsgBase> it( msgList ); *it; ++it ) 00361 { 00362 int idx = find(it.current()); 00363 assert( idx != -1); 00364 removeMsg(idx, imapQuiet); 00365 } 00366 } 00367 00368 //----------------------------------------------------------------------------- 00369 void FolderStorage::removeMsg(const TQPtrList<KMMessage>& msgList, bool imapQuiet) 00370 { 00371 for( TQPtrListIterator<KMMessage> it( msgList ); *it; ++it ) 00372 { 00373 int idx = find(it.current()); 00374 assert( idx != -1); 00375 removeMsg(idx, imapQuiet); 00376 } 00377 } 00378 00379 //----------------------------------------------------------------------------- 00380 void FolderStorage::removeMsg(int idx, bool) 00381 { 00382 //assert(idx>=0); 00383 if(idx < 0) 00384 { 00385 kdDebug(5006) << "FolderStorage::removeMsg() : idx < 0\n" << endl; 00386 return; 00387 } 00388 00389 KMMsgBase* mb = getMsgBase(idx); 00390 00391 TQ_UINT32 serNum = KMMsgDict::instance()->getMsgSerNum( folder(), idx ); 00392 if (serNum != 0) 00393 emit msgRemoved( folder(), serNum ); 00394 mb = takeIndexEntry( idx ); 00395 00396 setDirty( true ); 00397 needsCompact=true; // message is taken from here - needs to be compacted 00398 00399 if (mb->isUnread() || mb->isNew() || 00400 (folder() == kmkernel->outboxFolder())) { 00401 --mUnreadMsgs; 00402 if ( !mQuiet ) { 00403 // kdDebug( 5006 ) << "FolderStorage::msgStatusChanged" << endl; 00404 emit numUnreadMsgsChanged( folder() ); 00405 }else{ 00406 if ( !mEmitChangedTimer->isActive() ) { 00407 // kdDebug( 5006 )<< "EmitChangedTimer started" << endl; 00408 mEmitChangedTimer->start( 3000 ); 00409 } 00410 mChanged = true; 00411 } 00412 } 00413 --mTotalMsgs; 00414 00415 mSize = -1; 00416 TQString msgIdMD5 = mb->msgIdMD5(); 00417 emit msgRemoved( idx, msgIdMD5 ); 00418 emit msgRemoved( folder() ); 00419 } 00420 00421 00422 //----------------------------------------------------------------------------- 00423 KMMessage* FolderStorage::take(int idx) 00424 { 00425 KMMsgBase* mb; 00426 KMMessage* msg; 00427 00428 assert(idx>=0 && idx<=count()); 00429 00430 mb = getMsgBase(idx); 00431 if (!mb) return 0; 00432 if (!mb->isMessage()) readMsg(idx); 00433 TQ_UINT32 serNum = KMMsgDict::instance()->getMsgSerNum( folder(), idx ); 00434 emit msgRemoved( folder(), serNum ); 00435 00436 msg = (KMMessage*)takeIndexEntry(idx); 00437 00438 if (msg->isUnread() || msg->isNew() || 00439 ( folder() == kmkernel->outboxFolder() )) { 00440 --mUnreadMsgs; 00441 if ( !mQuiet ) { 00442 emit numUnreadMsgsChanged( folder() ); 00443 }else{ 00444 if ( !mEmitChangedTimer->isActive() ) { 00445 mEmitChangedTimer->start( 3000 ); 00446 } 00447 mChanged = true; 00448 } 00449 } 00450 --mTotalMsgs; 00451 msg->setParent(0); 00452 setDirty( true ); 00453 mSize = -1; 00454 needsCompact=true; // message is taken from here - needs to be compacted 00455 TQString msgIdMD5 = msg->msgIdMD5(); 00456 emit msgRemoved( idx, msgIdMD5 ); 00457 emit msgRemoved( folder() ); 00458 00459 return msg; 00460 } 00461 00462 void FolderStorage::take(TQPtrList<KMMessage> msgList) 00463 { 00464 for ( KMMessage* msg = msgList.first(); msg; msg = msgList.next() ) 00465 { 00466 if (msg->parent()) 00467 { 00468 int idx = msg->parent()->find(msg); 00469 if ( idx >= 0 ) 00470 take(idx); 00471 } 00472 } 00473 } 00474 00475 00476 //----------------------------------------------------------------------------- 00477 KMMessage* FolderStorage::getMsg(int idx) 00478 { 00479 if ( mOpenCount <= 0 ) { 00480 kdWarning(5006) << "FolderStorage::getMsg was called on a closed folder: " << folder()->prettyURL() << endl; 00481 return 0; 00482 } 00483 if ( idx < 0 || idx >= count() ) { 00484 kdWarning(5006) << "FolderStorage::getMsg was asked for an invalid index. idx =" << idx << " count()=" << count() << endl; 00485 return 0; 00486 } 00487 00488 KMMsgBase* mb = getMsgBase(idx); 00489 if (!mb) { 00490 kdWarning(5006) << "FolderStorage::getMsg, getMsgBase failed for index: " << idx << endl; 00491 return 0; 00492 } 00493 00494 KMMessage *msg = 0; 00495 bool undo = mb->enableUndo(); 00496 if (mb->isMessage()) { 00497 msg = ((KMMessage*)mb); 00498 } else { 00499 TQString mbSubject = mb->subject(); 00500 msg = readMsg(idx); 00501 // sanity check 00502 if (mCompactable && (!msg || (msg->subject().isEmpty() != mbSubject.isEmpty()))) { 00503 kdDebug(5006) << "Error: " << location() << 00504 " Index file is inconsistent with folder file. This should never happen." << endl; 00505 00506 // We can't recreate the index at this point, since that would invalidate the current 00507 // message list and delete KMMsgBase or KMMessage objects that are in use. 00508 // Do it later in KMFolderIndex::readIndexHeader() instead. 00509 mCompactable = false; // Don't compact 00510 writeConfig(); 00511 } 00512 00513 } 00514 // Either isMessage and we had a sernum, or readMsg gives us one 00515 // (via insertion into mMsgList). sernum == 0 may still occur due to 00516 // an outdated or corrupt IMAP cache. 00517 if ( msg->getMsgSerNum() == 0 ) { 00518 kdWarning(5006) << "FolderStorage::getMsg, message has no sernum, index: " << idx << endl; 00519 return 0; 00520 } 00521 msg->setEnableUndo(undo); 00522 msg->setComplete( true ); 00523 return msg; 00524 } 00525 00526 //----------------------------------------------------------------------------- 00527 KMMessage* FolderStorage::readTemporaryMsg(int idx) 00528 { 00529 if(!(idx >= 0 && idx <= count())) { 00530 kdDebug(5006) << k_funcinfo << "Invalid index " << idx << "!" << endl; 00531 return 0; 00532 } 00533 00534 KMMsgBase* mb = getMsgBase(idx); 00535 if (!mb) { 00536 kdDebug(5006) << k_funcinfo << "getMsgBase() for " << idx << " failed!" << endl; 00537 return 0; 00538 } 00539 00540 unsigned long sernum = mb->getMsgSerNum(); 00541 00542 KMMessage *msg = 0; 00543 bool undo = mb->enableUndo(); 00544 if (mb->isMessage()) { 00545 // the caller will delete it, so we must make a copy it 00546 msg = new KMMessage(*(KMMessage*)mb); 00547 msg->setMsgSerNum(sernum); 00548 msg->setComplete( true ); 00549 } else { 00550 // ## Those two lines need to be moved to a virtual method for KMFolderSearch, like readMsg 00551 msg = new KMMessage(*(KMMsgInfo*)mb); 00552 msg->setMsgSerNum(sernum); // before fromDwString so that readyToShow uses the right sernum 00553 msg->setComplete( true ); 00554 const DwString msgString = getDwString( idx ); 00555 if ( msgString.size() <= 0 ) { 00556 kdDebug(5006) << k_funcinfo << " Calling getDwString() failed!" << endl; 00557 } 00558 msg->fromDwString( msgString ); 00559 } 00560 msg->setEnableUndo(undo); 00561 return msg; 00562 } 00563 00564 00565 //----------------------------------------------------------------------------- 00566 KMMsgInfo* FolderStorage::unGetMsg(int idx) 00567 { 00568 KMMsgBase* mb; 00569 00570 if(!(idx >= 0 && idx <= count())) 00571 return 0; 00572 00573 mb = getMsgBase(idx); 00574 if (!mb) return 0; 00575 00576 00577 if (mb->isMessage()) { 00578 // Remove this message from all jobs' list it might still be on. 00579 // setIndexEntry deletes the message. 00580 KMMessage *msg = static_cast<KMMessage*>(mb); 00581 if ( msg->transferInProgress() ) return 0; 00582 ignoreJobsForMessage( msg ); 00583 return setIndexEntry( idx, msg ); 00584 } 00585 00586 return 0; 00587 } 00588 00589 00590 //----------------------------------------------------------------------------- 00591 bool FolderStorage::isMessage(int idx) 00592 { 00593 KMMsgBase* mb; 00594 if (!(idx >= 0 && idx <= count())) return false; 00595 mb = getMsgBase(idx); 00596 return (mb && mb->isMessage()); 00597 } 00598 00599 //----------------------------------------------------------------------------- 00600 FolderJob* FolderStorage::createJob( KMMessage *msg, FolderJob::JobType jt, 00601 KMFolder *folder, TQString partSpecifier, 00602 const AttachmentStrategy *as ) const 00603 { 00604 FolderJob * job = doCreateJob( msg, jt, folder, partSpecifier, as ); 00605 if ( job ) 00606 addJob( job ); 00607 return job; 00608 } 00609 00610 //----------------------------------------------------------------------------- 00611 FolderJob* FolderStorage::createJob( TQPtrList<KMMessage>& msgList, const TQString& sets, 00612 FolderJob::JobType jt, KMFolder *folder ) const 00613 { 00614 FolderJob * job = doCreateJob( msgList, sets, jt, folder ); 00615 if ( job ) 00616 addJob( job ); 00617 return job; 00618 } 00619 00620 //----------------------------------------------------------------------------- 00621 int FolderStorage::moveMsg(KMMessage* aMsg, int* aIndex_ret) 00622 { 00623 assert(aMsg != 0); 00624 KMFolder* msgParent = aMsg->parent(); 00625 00626 if (msgParent) 00627 msgParent->open("moveMsgSrc"); 00628 00629 open("moveMsgDest"); 00630 int rc = addMsg(aMsg, aIndex_ret); 00631 close("moveMsgDest"); 00632 00633 if (msgParent) 00634 msgParent->close("moveMsgSrc"); 00635 00636 return rc; 00637 } 00638 00639 //----------------------------------------------------------------------------- 00640 int FolderStorage::moveMsg(TQPtrList<KMMessage> msglist, int* aIndex_ret) 00641 { 00642 KMMessage* aMsg = msglist.first(); 00643 assert(aMsg != 0); 00644 KMFolder* msgParent = aMsg->parent(); 00645 00646 if (msgParent) 00647 msgParent->open("foldermovemsg"); 00648 00649 TQValueList<int> index; 00650 open("moveMsg"); 00651 int rc = addMsg(msglist, index); 00652 close("moveMsg"); 00653 // FIXME: we want to have a TQValueList to pass it back, so change this method 00654 if ( !index.isEmpty() ) 00655 aIndex_ret = &index.first(); 00656 00657 if (msgParent) 00658 msgParent->close("foldermovemsg"); 00659 00660 return rc; 00661 } 00662 00663 00664 //----------------------------------------------------------------------------- 00665 int FolderStorage::rename(const TQString& newName, KMFolderDir *newParent) 00666 { 00667 TQString oldLoc, oldIndexLoc, oldIdsLoc, newLoc, newIndexLoc, newIdsLoc; 00668 TQString oldSubDirLoc, newSubDirLoc; 00669 TQString oldName; 00670 int rc=0; 00671 KMFolderDir *oldParent; 00672 00673 assert(!newName.isEmpty()); 00674 00675 oldLoc = location(); 00676 oldIndexLoc = indexLocation(); 00677 oldSubDirLoc = folder()->subdirLocation(); 00678 oldIdsLoc = KMMsgDict::instance()->getFolderIdsLocation( *this ); 00679 TQString oldConfigString = "Folder-" + folder()->idString(); 00680 00681 close("rename", true); 00682 00683 oldName = folder()->fileName(); 00684 oldParent = folder()->parent(); 00685 if (newParent) 00686 folder()->setParent( newParent ); 00687 00688 folder()->setName(newName); 00689 newLoc = location(); 00690 newIndexLoc = indexLocation(); 00691 newSubDirLoc = folder()->subdirLocation(); 00692 newIdsLoc = KMMsgDict::instance()->getFolderIdsLocation( *this ); 00693 00694 if (::rename(TQFile::encodeName(oldLoc), TQFile::encodeName(newLoc))) { 00695 folder()->setName(oldName); 00696 folder()->setParent(oldParent); 00697 rc = errno; 00698 } 00699 else { 00700 // rename/move index file and index.sorted file 00701 if (!oldIndexLoc.isEmpty()) { 00702 ::rename(TQFile::encodeName(oldIndexLoc), TQFile::encodeName(newIndexLoc)); 00703 ::rename(TQFile::encodeName(oldIndexLoc) + ".sorted", 00704 TQFile::encodeName(newIndexLoc) + ".sorted"); 00705 } 00706 00707 // rename/move serial number file 00708 if (!oldIdsLoc.isEmpty()) 00709 ::rename(TQFile::encodeName(oldIdsLoc), TQFile::encodeName(newIdsLoc)); 00710 00711 // rename/move the subfolder directory 00712 KMFolderDir* child = 0; 00713 if( folder() ) 00714 child = folder()->child(); 00715 00716 if (!::rename(TQFile::encodeName(oldSubDirLoc), TQFile::encodeName(newSubDirLoc) )) { 00717 // now that the subfolder directory has been renamed and/or moved also 00718 // change the name that is stored in the corresponding KMFolderNode 00719 // (provide that the name actually changed) 00720 if( child && ( oldName != newName ) ) { 00721 child->setName( "." + TQFile::encodeName(newName) + ".directory" ); 00722 } 00723 } 00724 00725 // if the folder is being moved then move its node and, if necessary, also 00726 // the associated subfolder directory node to the new parent 00727 if (newParent) { 00728 if (oldParent->findRef( folder() ) != -1) 00729 oldParent->take(); 00730 newParent->inSort( folder() ); 00731 if ( child ) { 00732 if ( child->parent()->findRef( child ) != -1 ) 00733 child->parent()->take(); 00734 newParent->inSort( child ); 00735 child->setParent( newParent ); 00736 } 00737 } 00738 } 00739 00740 writeConfig(); 00741 00742 // delete the old entry as we get two entries with the same ID otherwise 00743 if ( oldConfigString != "Folder-" + folder()->idString() ) 00744 KMKernel::config()->deleteGroup( oldConfigString ); 00745 00746 emit locationChanged( oldLoc, newLoc ); 00747 emit nameChanged(); 00748 kmkernel->folderMgr()->contentsChanged(); 00749 emit closed(folder()); // let the ticket owners regain 00750 return rc; 00751 } 00752 00753 00754 //----------------------------------------------------------------------------- 00755 void FolderStorage::remove() 00756 { 00757 assert(!folder()->name().isEmpty()); 00758 00759 clearIndex( true, mExportsSernums ); // delete and remove from dict if necessary 00760 close("remove", true); 00761 00762 if ( mExportsSernums ) { 00763 KMMsgDict::mutableInstance()->removeFolderIds( *this ); 00764 mExportsSernums = false; // do not writeFolderIds after removal 00765 } 00766 unlink(TQFile::encodeName(indexLocation()) + ".sorted"); 00767 unlink(TQFile::encodeName(indexLocation())); 00768 00769 int rc = removeContents(); 00770 00771 needsCompact = false; //we are dead - no need to compact us 00772 00773 // Erase settings, otherwise they might interfer when recreating the folder 00774 KConfig* config = KMKernel::config(); 00775 config->deleteGroup( "Folder-" + folder()->idString() ); 00776 00777 emit closed(folder()); 00778 emit removed(folder(), (rc ? false : true)); 00779 } 00780 00781 00782 //----------------------------------------------------------------------------- 00783 int FolderStorage::expunge() 00784 { 00785 assert(!folder()->name().isEmpty()); 00786 00787 clearIndex( true, mExportsSernums ); // delete and remove from dict, if needed 00788 close( "expunge", true ); 00789 00790 if ( mExportsSernums ) 00791 KMMsgDict::mutableInstance()->removeFolderIds( *this ); 00792 if ( mAutoCreateIndex ) 00793 truncateIndex(); 00794 else unlink(TQFile::encodeName(indexLocation())); 00795 00796 int rc = expungeContents(); 00797 if (rc) return rc; 00798 00799 mDirty = false; 00800 needsCompact = false; //we're cleared and truncated no need to compact 00801 00802 mUnreadMsgs = 0; 00803 mTotalMsgs = 0; 00804 mSize = 0; 00805 emit numUnreadMsgsChanged( folder() ); 00806 if ( mAutoCreateIndex ) // FIXME Heh? - Till 00807 writeConfig(); 00808 emit changed(); 00809 emit expunged( folder() ); 00810 00811 return 0; 00812 } 00813 00814 //----------------------------------------------------------------------------- 00815 TQString FolderStorage::label() const 00816 { 00817 return folder()->label(); 00818 } 00819 00820 int FolderStorage::count(bool cache) const 00821 { 00822 if (cache && mTotalMsgs != -1) 00823 return mTotalMsgs; 00824 else 00825 return -1; 00826 } 00827 00828 //----------------------------------------------------------------------------- 00829 int FolderStorage::countUnread() 00830 { 00831 if (mGuessedUnreadMsgs > -1) 00832 return mGuessedUnreadMsgs; 00833 if (mUnreadMsgs > -1) 00834 return mUnreadMsgs; 00835 00836 readConfig(); 00837 00838 if (mUnreadMsgs > -1) 00839 return mUnreadMsgs; 00840 00841 open("countunread"); // will update unreadMsgs 00842 int unread = mUnreadMsgs; 00843 close("countunread"); 00844 return (unread > 0) ? unread : 0; 00845 } 00846 00847 TQ_INT64 FolderStorage::folderSize() const 00848 { 00849 if ( mSize != -1 ) { 00850 return mSize; 00851 } else { 00852 return doFolderSize(); 00853 } 00854 } 00855 00856 00857 /*virtual*/ 00858 bool FolderStorage::isCloseToQuota() const 00859 { 00860 return false; 00861 } 00862 00863 //----------------------------------------------------------------------------- 00864 void FolderStorage::msgStatusChanged(const KMMsgStatus oldStatus, 00865 const KMMsgStatus newStatus, int idx) 00866 { 00867 int oldUnread = 0; 00868 int newUnread = 0; 00869 00870 if (((oldStatus & KMMsgStatusUnread || oldStatus & KMMsgStatusNew) && 00871 !(oldStatus & KMMsgStatusIgnored)) || 00872 (folder() == kmkernel->outboxFolder())) 00873 oldUnread = 1; 00874 if (((newStatus & KMMsgStatusUnread || newStatus & KMMsgStatusNew) && 00875 !(newStatus & KMMsgStatusIgnored)) || 00876 (folder() == kmkernel->outboxFolder())) 00877 newUnread = 1; 00878 int deltaUnread = newUnread - oldUnread; 00879 00880 mDirtyTimer->changeInterval(mDirtyTimerInterval); 00881 if (deltaUnread != 0) { 00882 if (mUnreadMsgs < 0) mUnreadMsgs = 0; 00883 mUnreadMsgs += deltaUnread; 00884 if ( !mQuiet ) { 00885 emit numUnreadMsgsChanged( folder() ); 00886 }else{ 00887 if ( !mEmitChangedTimer->isActive() ) { 00888 mEmitChangedTimer->start( 3000 ); 00889 } 00890 mChanged = true; 00891 } 00892 TQ_UINT32 serNum = KMMsgDict::instance()->getMsgSerNum(folder(), idx); 00893 emit msgChanged( folder(), serNum, deltaUnread ); 00894 } 00895 } 00896 00897 //----------------------------------------------------------------------------- 00898 void FolderStorage::headerOfMsgChanged(const KMMsgBase* aMsg, int idx) 00899 { 00900 if (idx < 0) 00901 idx = aMsg->parent()->find( aMsg ); 00902 00903 if (idx >= 0 ) 00904 { 00905 if ( !mQuiet ) 00906 emit msgHeaderChanged(folder(), idx); 00907 else{ 00908 if ( !mEmitChangedTimer->isActive() ) { 00909 mEmitChangedTimer->start( 3000 ); 00910 } 00911 mChanged = true; 00912 } 00913 } else 00914 mChanged = true; 00915 } 00916 00917 //----------------------------------------------------------------------------- 00918 void FolderStorage::readConfig() 00919 { 00920 //kdDebug(5006)<<"#### READING CONFIG = "<< name() <<endl; 00921 KConfig* config = KMKernel::config(); 00922 KConfigGroupSaver saver(config, "Folder-" + folder()->idString()); 00923 if (mUnreadMsgs == -1) 00924 mUnreadMsgs = config->readNumEntry("UnreadMsgs", -1); 00925 if (mTotalMsgs == -1) 00926 mTotalMsgs = config->readNumEntry("TotalMsgs", -1); 00927 mCompactable = config->readBoolEntry("Compactable", true); 00928 if ( mSize == -1 ) 00929 mSize = config->readNum64Entry("FolderSize", -1); 00930 00931 int type = config->readNumEntry( "ContentsType", 0 ); 00932 if ( type < 0 || type > KMail::ContentsTypeLast ) type = 0; 00933 setContentsType( static_cast<KMail::FolderContentsType>( type ) ); 00934 00935 if( folder() ) folder()->readConfig( config ); 00936 } 00937 00938 //----------------------------------------------------------------------------- 00939 void FolderStorage::writeConfig() 00940 { 00941 KConfig* config = KMKernel::config(); 00942 KConfigGroupSaver saver(config, "Folder-" + folder()->idString()); 00943 config->writeEntry("UnreadMsgs", 00944 mGuessedUnreadMsgs == -1 ? mUnreadMsgs : mGuessedUnreadMsgs); 00945 config->writeEntry("TotalMsgs", mTotalMsgs); 00946 config->writeEntry("Compactable", mCompactable); 00947 config->writeEntry("ContentsType", mContentsType); 00948 config->writeEntry("FolderSize", mSize); 00949 00950 // Write the KMFolder parts 00951 if( folder() ) folder()->writeConfig( config ); 00952 00953 GlobalSettings::self()->requestSync(); 00954 } 00955 00956 //----------------------------------------------------------------------------- 00957 void FolderStorage::correctUnreadMsgsCount() 00958 { 00959 open("countunreadmsg"); 00960 close("countunreadmsg"); 00961 emit numUnreadMsgsChanged( folder() ); 00962 } 00963 00964 void FolderStorage::registerWithMessageDict() 00965 { 00966 mExportsSernums = true; 00967 readFolderIdsFile(); 00968 } 00969 00970 void FolderStorage::deregisterFromMessageDict() 00971 { 00972 writeFolderIdsFile(); 00973 mExportsSernums = false; 00974 } 00975 00976 void FolderStorage::readFolderIdsFile() 00977 { 00978 if ( !mExportsSernums ) return; 00979 if ( KMMsgDict::mutableInstance()->readFolderIds( *this ) == -1 ) { 00980 invalidateFolder(); 00981 } 00982 if ( !KMMsgDict::mutableInstance()->hasFolderIds( *this ) ) { 00983 invalidateFolder(); 00984 } 00985 } 00986 00987 void FolderStorage::invalidateFolder() 00988 { 00989 if ( !mExportsSernums ) return; 00990 unlink(TQFile::encodeName( indexLocation()) + ".sorted"); 00991 unlink(TQFile::encodeName( indexLocation()) + ".ids"); 00992 fillMessageDict(); 00993 KMMsgDict::mutableInstance()->writeFolderIds( *this ); 00994 emit invalidated( folder() ); 00995 } 00996 00997 00998 //----------------------------------------------------------------------------- 00999 int FolderStorage::writeFolderIdsFile() const 01000 { 01001 if ( !mExportsSernums ) return -1; 01002 return KMMsgDict::mutableInstance()->writeFolderIds( *this ); 01003 } 01004 01005 //----------------------------------------------------------------------------- 01006 int FolderStorage::touchFolderIdsFile() 01007 { 01008 if ( !mExportsSernums ) return -1; 01009 return KMMsgDict::mutableInstance()->touchFolderIds( *this ); 01010 } 01011 01012 //----------------------------------------------------------------------------- 01013 int FolderStorage::appendToFolderIdsFile( int idx ) 01014 { 01015 if ( !mExportsSernums ) return -1; 01016 int ret = 0; 01017 if ( count() == 1 ) { 01018 ret = KMMsgDict::mutableInstance()->writeFolderIds( *this ); 01019 } else { 01020 ret = KMMsgDict::mutableInstance()->appendToFolderIds( *this, idx ); 01021 } 01022 return ret; 01023 } 01024 01025 void FolderStorage::replaceMsgSerNum( unsigned long sernum, KMMsgBase* msg, int idx ) 01026 { 01027 if ( !mExportsSernums ) return; 01028 KMMsgDict::mutableInstance()->replace( sernum, msg, idx ); 01029 } 01030 01031 void FolderStorage::setRDict( KMMsgDictREntry *rentry ) const 01032 { 01033 if ( ! mExportsSernums ) 01034 kdDebug(5006) << "WTF, this FolderStorage should be invisible to the msgdict, who is calling us?" << kdBacktrace() << endl; 01035 assert( mExportsSernums ); // otherwise things are very wrong 01036 if ( rentry == mRDict ) 01037 return; 01038 KMMsgDict::deleteRentry( mRDict ); 01039 mRDict = rentry; 01040 } 01041 01042 //----------------------------------------------------------------------------- 01043 void FolderStorage::setStatus(int idx, KMMsgStatus status, bool toggle) 01044 { 01045 KMMsgBase *msg = getMsgBase(idx); 01046 if ( msg ) { 01047 if (toggle) 01048 msg->toggleStatus(status, idx); 01049 else 01050 msg->setStatus(status, idx); 01051 } 01052 } 01053 01054 01055 //----------------------------------------------------------------------------- 01056 void FolderStorage::setStatus(TQValueList<int>& ids, KMMsgStatus status, bool toggle) 01057 { 01058 for ( TQValueList<int>::Iterator it = ids.begin(); it != ids.end(); ++it ) 01059 { 01060 FolderStorage::setStatus(*it, status, toggle); 01061 } 01062 } 01063 01064 void FolderStorage::ignoreJobsForMessage( KMMessage *msg ) 01065 { 01066 if ( !msg || msg->transferInProgress() ) 01067 return; 01068 01069 TQPtrListIterator<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 //----------------------------------------------------------------------------- 01086 void FolderStorage::removeJobs() 01087 { 01088 mJobList.setAutoDelete( true ); 01089 mJobList.clear(); 01090 mJobList.setAutoDelete( false ); 01091 } 01092 01093 01094 01095 //----------------------------------------------------------------------------- 01096 void FolderStorage::updateChildrenState() 01097 { 01098 if ( folder() && folder()->child() ) 01099 { 01100 if ( kmkernel->folderMgr()->folderCount( folder()->child() ) > 0 ) 01101 setHasChildren( HasChildren ); 01102 else 01103 setHasChildren( HasNoChildren ); 01104 } 01105 } 01106 01107 //----------------------------------------------------------------------------- 01108 void FolderStorage::setNoChildren( bool aNoChildren ) 01109 { 01110 mNoChildren = aNoChildren; 01111 if ( aNoChildren ) 01112 setHasChildren( HasNoChildren ); 01113 } 01114 01115 //----------------------------------------------------------------------------- 01116 void FolderStorage::setContentsType( KMail::FolderContentsType type, bool quiet ) 01117 { 01118 if ( type != mContentsType ) { 01119 mContentsType = type; 01120 if ( !quiet ) 01121 emit contentsTypeChanged( type ); 01122 } 01123 } 01124 01125 //----------------------------------------------------------------------------- 01126 void FolderStorage::search( const KMSearchPattern* pattern ) 01127 { 01128 mSearchPattern = pattern; 01129 mCurrentSearchedMsg = 0; 01130 if ( pattern ) 01131 slotProcessNextSearchBatch(); 01132 } 01133 01134 void FolderStorage::slotProcessNextSearchBatch() 01135 { 01136 if ( !mSearchPattern ) 01137 return; 01138 TQValueList<TQ_UINT32> matchingSerNums; 01139 const int end = TQMIN( mCurrentSearchedMsg + 15, count() ); 01140 for ( int i = mCurrentSearchedMsg; i < end; ++i ) 01141 { 01142 TQ_UINT32 serNum = KMMsgDict::instance()->getMsgSerNum( folder(), i ); 01143 if ( mSearchPattern->matches( serNum ) ) 01144 matchingSerNums.append( serNum ); 01145 } 01146 mCurrentSearchedMsg = end; 01147 bool complete = ( end >= count() ); 01148 emit searchResult( folder(), matchingSerNums, mSearchPattern, complete ); 01149 if ( !complete ) 01150 TQTimer::singleShot( 0, this, TQT_SLOT(slotProcessNextSearchBatch()) ); 01151 } 01152 01153 //----------------------------------------------------------------------------- 01154 void FolderStorage::search( const KMSearchPattern* pattern, TQ_UINT32 serNum ) 01155 { 01156 bool matches = pattern && pattern->matches( serNum ); 01157 01158 emit searchDone( folder(), serNum, pattern, matches ); 01159 } 01160 01161 //----------------------------------------------------------------------------- 01162 int FolderStorage::addMsg( TQPtrList<KMMessage>& msgList, TQValueList<int>& index_ret ) 01163 { 01164 int ret = 0; 01165 int index; 01166 for ( TQPtrListIterator<KMMessage> it( msgList ); *it; ++it ) 01167 { 01168 int aret = addMsg( *it, &index ); 01169 index_ret << index; 01170 if ( aret != 0 ) // error condition 01171 ret = aret; 01172 } 01173 return ret; 01174 } 01175 01176 //----------------------------------------------------------------------------- 01177 bool FolderStorage::isMoveable() const 01178 { 01179 return ( folder()->isSystemFolder() ) ? false : true; 01180 } 01181 01182 01183 /*virtual*/ 01184 KMAccount* FolderStorage::account() const 01185 { 01186 return 0; 01187 } 01188 01189 bool FolderStorage::mailCheckInProgress() const 01190 { 01191 return false; 01192 } 01193 01194 bool FolderStorage::canDeleteMessages() const 01195 { 01196 return !isReadOnly(); 01197 } 01198 01199 void FolderStorage::setNoContent(bool aNoContent) 01200 { 01201 const bool changed = aNoContent != mNoContent; 01202 mNoContent = aNoContent; 01203 if ( changed ) 01204 emit noContentChanged(); 01205 } 01206 01207 #include "folderstorage.moc"