kmail

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"