kmail Library API Documentation

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., 59 Temple Place - Suite 330,
00021     Boston, MA 02111-1307, 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 Qt library by Trolltech AS, Norway (or with modified versions
00026     of Qt that use the same license as Qt), 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     Qt.  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 
00040 #include "kmfolderimap.h" //for the nasty imap hacks, FIXME
00041 #include "undostack.h"
00042 #include "kmmsgdict.h"
00043 #include "kmfoldermgr.h"
00044 #include "kmkernel.h"
00045 #include "kmcommands.h"
00046 #include "kmailicalifaceimpl.h"
00047 
00048 #include <klocale.h>
00049 #include <kconfig.h>
00050 #include <kdebug.h>
00051 
00052 #include <qfile.h>
00053 #include <qregexp.h>
00054 
00055 #include <mimelib/mimepp.h>
00056 #include <errno.h>
00057 #include "globalsettings.h"
00058 
00059 //-----------------------------------------------------------------------------
00060 
00061 FolderStorage::FolderStorage( KMFolder* folder, const char* aName )
00062   : QObject( folder, aName ), mFolder( folder )
00063 {
00064   mOpenCount      = 0;
00065   mQuiet      = 0;
00066   mChanged        = FALSE;
00067   mAutoCreateIndex= TRUE;
00068   folder->setType( "plain" );
00069   mAcctList       = 0;
00070   mDirty          = FALSE;
00071   mUnreadMsgs      = -1;
00072   mGuessedUnreadMsgs = -1;
00073   mTotalMsgs      = -1;
00074   needsCompact    = FALSE;
00075   mConvertToUtf8  = FALSE;
00076   mCompactable     = TRUE;
00077   mNoContent      = FALSE;
00078   mNoChildren     = FALSE;
00079   mRDict = 0;
00080   mDirtyTimer = new QTimer(this);
00081   connect(mDirtyTimer, SIGNAL(timeout()),
00082       this, SLOT(updateIndex()));
00083   mHasChildren = HasNoChildren;
00084   mContentsType = KMail::ContentsTypeMail;
00085 }
00086 
00087 //-----------------------------------------------------------------------------
00088 FolderStorage::~FolderStorage()
00089 {
00090   delete mAcctList;
00091   mJobList.setAutoDelete( true );
00092   QObject::disconnect( SIGNAL(destroyed(QObject*)), this, 0 );
00093   mJobList.clear();
00094   KMMsgDict::deleteRentry(mRDict);
00095 }
00096 
00097 
00098 //-----------------------------------------------------------------------------
00099 QString FolderStorage::dotEscape(const QString& aStr)
00100 {
00101   if (aStr[0] != '.') return aStr;
00102   return aStr.left(aStr.find(QRegExp("[^\\.]"))) + aStr;
00103 }
00104 
00105 void FolderStorage::addJob( FolderJob* job ) const
00106 {
00107   QObject::connect( job, SIGNAL(destroyed(QObject*)),
00108                     SLOT(removeJob(QObject*)) );
00109   mJobList.append( job );
00110 }
00111 
00112 void FolderStorage::removeJob( QObject* job )
00113 {
00114   mJobList.remove( static_cast<FolderJob*>( job ) );
00115 }
00116 
00117 
00118 //-----------------------------------------------------------------------------
00119 QString FolderStorage::location() const
00120 {
00121   QString sLocation(const_cast<FolderStorage*>(this)->folder()->path());
00122 
00123   if (!sLocation.isEmpty()) sLocation += '/';
00124   sLocation += dotEscape(fileName());
00125 
00126   return sLocation;
00127 }
00128 
00129 QString FolderStorage::fileName() const
00130 {
00131   return mFolder->name();
00132 }
00133 
00134 
00135 
00136 //-----------------------------------------------------------------------------
00137 void FolderStorage::setAutoCreateIndex(bool autoIndex)
00138 {
00139   mAutoCreateIndex = autoIndex;
00140 }
00141 
00142 //-----------------------------------------------------------------------------
00143 void FolderStorage::setDirty(bool f)
00144 {
00145   mDirty = f;
00146   if (mDirty  && mAutoCreateIndex)
00147     mDirtyTimer->changeInterval( mDirtyTimerInterval );
00148   else
00149     mDirtyTimer->stop();
00150 }
00151 
00152 //-----------------------------------------------------------------------------
00153 void FolderStorage::markNewAsUnread()
00154 {
00155   KMMsgBase* msgBase;
00156   int i;
00157 
00158   for (i=0; i< count(); ++i)
00159   {
00160     if (!(msgBase = getMsgBase(i))) continue;
00161     if (msgBase->isNew())
00162     {
00163       msgBase->setStatus(KMMsgStatusUnread);
00164       msgBase->setDirty(TRUE);
00165     }
00166   }
00167 }
00168 
00169 void FolderStorage::markUnreadAsRead()
00170 {
00171   KMMsgBase* msgBase;
00172   SerNumList serNums;
00173 
00174   for (int i=count()-1; i>=0; --i)
00175   {
00176     msgBase = getMsgBase(i);
00177     assert(msgBase);
00178     if (msgBase->isNew() || msgBase->isUnread())
00179     {
00180       serNums.append( msgBase->getMsgSerNum() );
00181     }
00182   }
00183   if (serNums.empty())
00184     return;
00185 
00186   KMCommand *command = new KMSetStatusCommand( KMMsgStatusRead, serNums );
00187   command->start();
00188 }
00189 
00190 //-----------------------------------------------------------------------------
00191 void FolderStorage::quiet(bool beQuiet)
00192 {
00193   if (beQuiet)
00194     mQuiet++;
00195   else {
00196     mQuiet--;
00197     if (mQuiet <= 0)
00198     {
00199       mQuiet = 0;
00200       if (mChanged)
00201        emit changed();
00202       mChanged = FALSE;
00203     }
00204   }
00205 }
00206 
00207 //-----------------------------------------------------------------------------
00208 
00209 // Needed to use QSortedList in reduceSize()
00210 
00212 int operator<( KMMsgBase & m1, KMMsgBase & m2 )
00213 {
00214   return (m1.date() < m2.date());
00215 }
00216 
00218 int operator==( KMMsgBase & m1, KMMsgBase & m2 )
00219 {
00220   return (m1.date() == m2.date());
00221 }
00222 
00223 
00224 //-----------------------------------------------------------------------------
00225 int FolderStorage::expungeOldMsg(int days)
00226 {
00227   int i, msgnb=0;
00228   time_t msgTime, maxTime;
00229   const KMMsgBase* mb;
00230   QValueList<int> rmvMsgList;
00231 
00232   maxTime = time(0) - days * 3600 * 24;
00233 
00234   for (i=count()-1; i>=0; i--) {
00235     mb = getMsgBase(i);
00236     assert(mb);
00237     msgTime = mb->date();
00238 
00239     if (msgTime < maxTime) {
00240       //kdDebug(5006) << "deleting msg " << i << " : " << mb->subject() << " - " << mb->dateStr(); // << endl;
00241       removeMsg( i );
00242       msgnb++;
00243     }
00244   }
00245   return msgnb;
00246 }
00247 
00248 //-----------------------------------------------------------------------------
00249 void FolderStorage::emitMsgAddedSignals(int idx)
00250 {
00251   Q_UINT32 serNum = kmkernel->msgDict()->getMsgSerNum( folder() , idx );
00252   if (!mQuiet) {
00253     emit msgAdded(idx);
00254   } else {
00255     mChanged=true;
00256   }
00257   emit msgAdded( folder(), serNum );
00258 }
00259 
00260 //-----------------------------------------------------------------------------
00261 bool FolderStorage::canAddMsgNow(KMMessage* aMsg, int* aIndex_ret)
00262 {
00263   if (aIndex_ret) *aIndex_ret = -1;
00264   KMFolder *msgParent = aMsg->parent();
00265   // If the message has a parent and is in transfer, bail out. If it does not
00266   // have a parent we want to be able to add it even if it is in transfer.
00267   if (aMsg->transferInProgress() && msgParent)
00268       return false;
00269   if (!aMsg->isComplete() && msgParent && msgParent->folderType() == KMFolderTypeImap)
00270   {
00271     FolderJob *job = msgParent->createJob(aMsg);
00272     connect(job, SIGNAL(messageRetrieved(KMMessage*)),
00273             SLOT(reallyAddMsg(KMMessage*)));
00274     job->start();
00275     aMsg->setTransferInProgress(TRUE);
00276     return FALSE;
00277   }
00278   return TRUE;
00279 }
00280 
00281 
00282 //-----------------------------------------------------------------------------
00283 void FolderStorage::reallyAddMsg(KMMessage* aMsg)
00284 {
00285   if (!aMsg) // the signal that is connected can call with aMsg=0
00286     return;
00287   aMsg->setTransferInProgress(FALSE);
00288   KMFolder *aFolder = aMsg->parent();
00289   int index;
00290   ulong serNum = aMsg->getMsgSerNum();
00291   bool undo = aMsg->enableUndo();
00292   addMsg(aMsg, &index);
00293   if (index < 0) return;
00294   unGetMsg(index);
00295   if (undo)
00296   {
00297     kmkernel->undoStack()->pushSingleAction( serNum, aFolder, folder() );
00298   }
00299 }
00300 
00301 
00302 //-----------------------------------------------------------------------------
00303 void FolderStorage::reallyAddCopyOfMsg(KMMessage* aMsg)
00304 {
00305   aMsg->setParent( 0 );
00306   aMsg->setTransferInProgress( false );
00307   addMsg( aMsg );
00308   unGetMsg( count() - 1 );
00309 }
00310 
00311 int FolderStorage::find( const KMMessage * msg ) const {
00312   return find( &msg->toMsgBase() );
00313 }
00314 
00315 //-----------------------------------------------------------------------------
00316 void FolderStorage::removeMsg(const QPtrList<KMMsgBase>& msgList, bool imapQuiet)
00317 {
00318   for( QPtrListIterator<KMMsgBase> it( msgList ); *it; ++it )
00319   {
00320     int idx = find(it.current());
00321     assert( idx != -1);
00322     removeMsg(idx, imapQuiet);
00323   }
00324 }
00325 
00326 //-----------------------------------------------------------------------------
00327 void FolderStorage::removeMsg(const QPtrList<KMMessage>& msgList, bool imapQuiet)
00328 {
00329   for( QPtrListIterator<KMMessage> it( msgList ); *it; ++it )
00330   {
00331     int idx = find(it.current());
00332     assert( idx != -1);
00333     removeMsg(idx, imapQuiet);
00334   }
00335 }
00336 
00337 //-----------------------------------------------------------------------------
00338 void FolderStorage::removeMsg(int idx, bool)
00339 {
00340   //assert(idx>=0);
00341   if(idx < 0)
00342   {
00343     kdDebug(5006) << "FolderStorage::removeMsg() : idx < 0\n" << endl;
00344     return;
00345   }
00346 
00347   KMMsgBase* mb = getMsgBase(idx);
00348 
00349   Q_UINT32 serNum = kmkernel->msgDict()->getMsgSerNum( folder(), idx );
00350   if (serNum != 0)
00351     emit msgRemoved( folder(), serNum );
00352   mb = takeIndexEntry( idx );
00353 
00354   setDirty( true );
00355   needsCompact=true; // message is taken from here - needs to be compacted
00356 
00357   if (mb->isUnread() || mb->isNew() ||
00358       (folder() == kmkernel->outboxFolder())) {
00359     --mUnreadMsgs;
00360     emit numUnreadMsgsChanged( folder() );
00361   }
00362   --mTotalMsgs;
00363 
00364   QString msgIdMD5 = mb->msgIdMD5();
00365   QString strippedSubjMD5 = mb->strippedSubjectMD5();
00366   if (strippedSubjMD5.isEmpty()) {
00367      mb->initStrippedSubjectMD5();
00368      strippedSubjMD5 = mb->strippedSubjectMD5();
00369   }
00370   emit msgRemoved(idx, msgIdMD5, strippedSubjMD5);
00371   emit msgRemoved( folder() );
00372 }
00373 
00374 
00375 //-----------------------------------------------------------------------------
00376 KMMessage* FolderStorage::take(int idx)
00377 {
00378   KMMsgBase* mb;
00379   KMMessage* msg;
00380 
00381   assert(idx>=0 && idx<=count());
00382 
00383   mb = getMsgBase(idx);
00384   if (!mb) return 0;
00385   if (!mb->isMessage()) readMsg(idx);
00386   Q_UINT32 serNum = kmkernel->msgDict()->getMsgSerNum( folder(), idx );
00387   emit msgRemoved( folder(), serNum );
00388 
00389   msg = (KMMessage*)takeIndexEntry(idx);
00390 
00391   if (msg->isUnread() || msg->isNew() ||
00392       ( folder() == kmkernel->outboxFolder() )) {
00393     --mUnreadMsgs;
00394     emit numUnreadMsgsChanged( folder() );
00395   }
00396   --mTotalMsgs;
00397   msg->setParent(0);
00398   setDirty( true );
00399   needsCompact=true; // message is taken from here - needs to be compacted
00400   QString msgIdMD5 = msg->msgIdMD5();
00401   QString strippedSubjMD5 = msg->strippedSubjectMD5();
00402   if (strippedSubjMD5.isEmpty()) {
00403      msg->initStrippedSubjectMD5();
00404      strippedSubjMD5 = msg->strippedSubjectMD5();
00405   }
00406   emit msgRemoved(idx, msgIdMD5, strippedSubjMD5);
00407   emit msgRemoved( folder() );
00408 
00409   return msg;
00410 }
00411 
00412 void FolderStorage::take(QPtrList<KMMessage> msgList)
00413 {
00414   for ( KMMessage* msg = msgList.first(); msg; msg = msgList.next() )
00415   {
00416     if (msg->parent())
00417     {
00418       int idx = msg->parent()->find(msg);
00419       assert( idx != -1);
00420       FolderStorage::take(idx);
00421     }
00422   }
00423 }
00424 
00425 
00426 //-----------------------------------------------------------------------------
00427 KMMessage* FolderStorage::getMsg(int idx)
00428 {
00429   if(!(idx >= 0 && idx <= count()))
00430     return 0;
00431 
00432   KMMsgBase* mb = getMsgBase(idx);
00433   if (!mb) return 0;
00434 
00435   KMMessage *msg = 0;
00436   bool undo = mb->enableUndo();
00437   if (mb->isMessage()) {
00438       msg = ((KMMessage*)mb);
00439   } else {
00440       QString mbSubject = mb->subject();
00441       msg = readMsg(idx);
00442       // sanity check
00443       if (mCompactable && (!msg || (msg->subject().isEmpty() != mbSubject.isEmpty()))) {
00444       kdDebug(5006) << "Error: " << location() <<
00445       " Index file is inconsistent with folder file. This should never happen." << endl;
00446       mCompactable = FALSE; // Don't compact
00447       writeConfig();
00448       }
00449 
00450   }
00451   msg->setEnableUndo(undo);
00452 
00453   // Can't happen. Either isMessage and we had a sernum, or readMsg gives us one
00454   // (via insertion into mMsgList).
00455   if (msg->getMsgSerNum() == 0) {
00456     msg->setMsgSerNum(kmkernel->msgDict()->insert(0, msg, idx));
00457     kdDebug(5006) << "Serial number generated for message in folder "
00458                   << label() << endl;
00459   }
00460   msg->setComplete( true );
00461   return msg;
00462 }
00463 
00464 //-----------------------------------------------------------------------------
00465 KMMessage* FolderStorage::readTemporaryMsg(int idx)
00466 {
00467   if(!(idx >= 0 && idx <= count()))
00468     return 0;
00469 
00470   KMMsgBase* mb = getMsgBase(idx);
00471   if (!mb) return 0;
00472 
00473   unsigned long sernum = mb->getMsgSerNum();
00474 
00475   KMMessage *msg = 0;
00476   bool undo = mb->enableUndo();
00477   if (mb->isMessage()) {
00478     // the caller will delete it, so we must make a copy it
00479     msg = new KMMessage(*(KMMessage*)mb);
00480     msg->setMsgSerNum(sernum);
00481   } else {
00482     // ## Those three lines need to be moved to a virtual method for KMFolderSearch, like readMsg
00483     msg = new KMMessage(*(KMMsgInfo*)mb);
00484     msg->setMsgSerNum(sernum); // before fromDwString so that readyToShow uses the right sernum
00485     msg->fromDwString(getDwString(idx));
00486   }
00487   msg->setEnableUndo(undo);
00488   msg->setComplete( true );
00489   return msg;
00490 }
00491 
00492 
00493 //-----------------------------------------------------------------------------
00494 KMMsgInfo* FolderStorage::unGetMsg(int idx)
00495 {
00496   KMMsgBase* mb;
00497 
00498   if(!(idx >= 0 && idx <= count()))
00499     return 0;
00500 
00501   mb = getMsgBase(idx);
00502   if (!mb) return 0;
00503 
00504 
00505   if (mb->isMessage()) {
00506     // Remove this message from all jobs' list it might still be on.
00507     // setIndexEntry deletes the message.
00508     KMMessage *msg = static_cast<KMMessage*>(mb);
00509     if ( msg->transferInProgress() ) return 0;
00510     ignoreJobsForMessage( msg );
00511     return setIndexEntry( idx, msg );
00512   }
00513 
00514   return 0;
00515 }
00516 
00517 
00518 //-----------------------------------------------------------------------------
00519 bool FolderStorage::isMessage(int idx)
00520 {
00521   KMMsgBase* mb;
00522   if (!(idx >= 0 && idx <= count())) return FALSE;
00523   mb = getMsgBase(idx);
00524   return (mb && mb->isMessage());
00525 }
00526 
00527 //-----------------------------------------------------------------------------
00528 FolderJob* FolderStorage::createJob( KMMessage *msg, FolderJob::JobType jt,
00529                                 KMFolder *folder, QString partSpecifier,
00530                                 const AttachmentStrategy *as ) const
00531 {
00532   FolderJob * job = doCreateJob( msg, jt, folder, partSpecifier, as );
00533   if ( job )
00534     addJob( job );
00535   return job;
00536 }
00537 
00538 //-----------------------------------------------------------------------------
00539 FolderJob* FolderStorage::createJob( QPtrList<KMMessage>& msgList, const QString& sets,
00540                                 FolderJob::JobType jt, KMFolder *folder ) const
00541 {
00542   FolderJob * job = doCreateJob( msgList, sets, jt, folder );
00543   if ( job )
00544     addJob( job );
00545   return job;
00546 }
00547 
00548 //-----------------------------------------------------------------------------
00549 int FolderStorage::moveMsg(KMMessage* aMsg, int* aIndex_ret)
00550 {
00551   assert(aMsg != 0);
00552   KMFolder* msgParent = aMsg->parent();
00553 
00554   if (msgParent)
00555     msgParent->open();
00556 
00557   open();
00558   int rc = addMsg(aMsg, aIndex_ret);
00559   close();
00560 
00561   if (msgParent)
00562     msgParent->close();
00563 
00564   return rc;
00565 }
00566 
00567 //-----------------------------------------------------------------------------
00568 int FolderStorage::moveMsg(QPtrList<KMMessage> msglist, int* aIndex_ret)
00569 {
00570   KMMessage* aMsg = msglist.first();
00571   assert(aMsg != 0);
00572   KMFolder* msgParent = aMsg->parent();
00573 
00574   if (msgParent)
00575     msgParent->open();
00576 
00577   open();
00578   //FIXME : is it always imap ?
00579   int rc = static_cast<KMFolderImap*>(this)->addMsg(msglist, aIndex_ret); //yuck: Don
00580   close();
00581 
00582   if (msgParent)
00583     msgParent->close();
00584 
00585   return rc;
00586 }
00587 
00588 
00589 //-----------------------------------------------------------------------------
00590 int FolderStorage::rename(const QString& newName, KMFolderDir *newParent)
00591 {
00592   QString oldLoc, oldIndexLoc, oldIdsLoc, newLoc, newIndexLoc, newIdsLoc;
00593   QString oldSubDirLoc, newSubDirLoc;
00594   QString oldName;
00595   int rc=0, openCount=mOpenCount;
00596   KMFolderDir *oldParent;
00597 
00598   assert(!newName.isEmpty());
00599 
00600   oldLoc = location();
00601   oldIndexLoc = indexLocation();
00602   oldSubDirLoc = folder()->subdirLocation();
00603   if (kmkernel->msgDict())
00604     oldIdsLoc = kmkernel->msgDict()->getFolderIdsLocation( folder() );
00605   QString oldConfigString = "Folder-" + folder()->idString();
00606 
00607   close(TRUE);
00608 
00609   oldName = folder()->fileName();
00610   oldParent = folder()->parent();
00611   if (newParent)
00612     folder()->setParent( newParent );
00613 
00614   folder()->setName(newName);
00615   newLoc = location();
00616   newIndexLoc = indexLocation();
00617   newSubDirLoc = folder()->subdirLocation();
00618   if (kmkernel->msgDict())
00619     newIdsLoc = kmkernel->msgDict()->getFolderIdsLocation( folder() );
00620 
00621   if (::rename(QFile::encodeName(oldLoc), QFile::encodeName(newLoc))) {
00622     folder()->setName(oldName);
00623     folder()->setParent(oldParent);
00624     rc = errno;
00625   }
00626   else {
00627     // rename/move index file and index.sorted file
00628     if (!oldIndexLoc.isEmpty()) {
00629       ::rename(QFile::encodeName(oldIndexLoc), QFile::encodeName(newIndexLoc));
00630       ::rename(QFile::encodeName(oldIndexLoc) + ".sorted",
00631                QFile::encodeName(newIndexLoc) + ".sorted");
00632     }
00633 
00634     // rename/move serial number file
00635     if (!oldIdsLoc.isEmpty())
00636       ::rename(QFile::encodeName(oldIdsLoc), QFile::encodeName(newIdsLoc));
00637 
00638     // rename/move the subfolder directory
00639     KMFolderDir* child = 0;
00640     if( folder() )
00641       child = folder()->child();
00642 
00643     if (!::rename(QFile::encodeName(oldSubDirLoc), QFile::encodeName(newSubDirLoc) )) {
00644       // now that the subfolder directory has been renamed and/or moved also
00645       // change the name that is stored in the corresponding KMFolderNode
00646       // (provide that the name actually changed)
00647       if( child && ( oldName != newName ) ) {
00648         child->setName( "." + QFile::encodeName(newName) + ".directory" );
00649       }
00650     }
00651 
00652     // if the folder is being moved then move its node and, if necessary, also
00653     // the associated subfolder directory node to the new parent
00654     if (newParent) {
00655       if (oldParent->findRef( folder() ) != -1)
00656         oldParent->take();
00657       newParent->inSort( folder() );
00658       if ( child ) {
00659         if ( child->parent()->findRef( child ) != -1 )
00660           child->parent()->take();
00661         newParent->inSort( child );
00662         child->setParent( newParent );
00663       }
00664     }
00665   }
00666 
00667   if (openCount > 0)
00668   {
00669     open();
00670     mOpenCount = openCount;
00671   }
00672   writeConfig();
00673 
00674   // delete the old entry as we get two entries with the same ID otherwise
00675   KMKernel::config()->deleteGroup( oldConfigString );
00676 
00677   emit locationChanged( oldLoc, newLoc );
00678   emit nameChanged();
00679   return rc;
00680 }
00681 
00682 
00683 //-----------------------------------------------------------------------------
00684 void FolderStorage::remove()
00685 {
00686   assert(!folder()->name().isEmpty());
00687 
00688   clearIndex(true, true); // delete and remove from dict
00689   close(TRUE);
00690 
00691   if (kmkernel->msgDict()) kmkernel->msgDict()->removeFolderIds( folder() );
00692   unlink(QFile::encodeName(indexLocation()) + ".sorted");
00693   unlink(QFile::encodeName(indexLocation()));
00694 
00695   int rc = removeContents();
00696 
00697   needsCompact = false; //we are dead - no need to compact us
00698 
00699   // Erase settings, otherwise they might interfer when recreating the folder
00700   KConfig* config = KMKernel::config();
00701   config->deleteGroup( "Folder-" + folder()->idString() );
00702 
00703   emit removed(folder(), (rc ? false : true));
00704 }
00705 
00706 
00707 //-----------------------------------------------------------------------------
00708 int FolderStorage::expunge()
00709 {
00710   int openCount = mOpenCount;
00711 
00712   assert(!folder()->name().isEmpty());
00713 
00714   clearIndex(true, true);   // delete and remove from dict
00715   close(TRUE);
00716 
00717   kmkernel->msgDict()->removeFolderIds( folder() );
00718   if (mAutoCreateIndex)
00719     truncateIndex();
00720   else unlink(QFile::encodeName(indexLocation()));
00721 
00722   int rc = expungeContents();
00723   if (rc) return rc;
00724 
00725   mDirty = FALSE;
00726   needsCompact = false; //we're cleared and truncated no need to compact
00727 
00728   if (openCount > 0)
00729   {
00730     open();
00731     mOpenCount = openCount;
00732   }
00733 
00734   mUnreadMsgs = 0;
00735   mTotalMsgs = 0;
00736   emit numUnreadMsgsChanged( folder() );
00737   if (mAutoCreateIndex)
00738     writeConfig();
00739   emit changed();
00740   emit expunged( folder() );
00741 
00742   return 0;
00743 }
00744 
00745 
00746 //-----------------------------------------------------------------------------
00747 const char* FolderStorage::type() const
00748 {
00749   if (mAcctList) return "In";
00750   return folder()->KMFolderNode::type();
00751 }
00752 
00753 
00754 //-----------------------------------------------------------------------------
00755 QString FolderStorage::label() const
00756 {
00757   return folder()->label();
00758 }
00759 
00760 int FolderStorage::count(bool cache) const
00761 {
00762   if (cache && mTotalMsgs != -1)
00763     return mTotalMsgs;
00764   else
00765     return -1;
00766 }
00767 
00768 //-----------------------------------------------------------------------------
00769 int FolderStorage::countUnread()
00770 {
00771   if (mGuessedUnreadMsgs > -1)
00772     return mGuessedUnreadMsgs;
00773   if (mUnreadMsgs > -1)
00774     return mUnreadMsgs;
00775 
00776   readConfig();
00777 
00778   if (mUnreadMsgs > -1)
00779     return mUnreadMsgs;
00780 
00781   open(); // will update unreadMsgs
00782   int unread = mUnreadMsgs;
00783   close();
00784   return (unread > 0) ? unread : 0;
00785 }
00786 
00787 //-----------------------------------------------------------------------------
00788 void FolderStorage::msgStatusChanged(const KMMsgStatus oldStatus,
00789   const KMMsgStatus newStatus, int idx)
00790 {
00791   int oldUnread = 0;
00792   int newUnread = 0;
00793 
00794   if (oldStatus & KMMsgStatusUnread || oldStatus & KMMsgStatusNew ||
00795       (folder() == kmkernel->outboxFolder()))
00796     oldUnread = 1;
00797   if (newStatus & KMMsgStatusUnread || newStatus & KMMsgStatusNew ||
00798       (folder() == kmkernel->outboxFolder()))
00799     newUnread = 1;
00800   int deltaUnread = newUnread - oldUnread;
00801 
00802   mDirtyTimer->changeInterval(mDirtyTimerInterval);
00803   if (deltaUnread != 0) {
00804     if (mUnreadMsgs < 0) mUnreadMsgs = 0;
00805     mUnreadMsgs += deltaUnread;
00806     if ( !mQuiet )
00807       emit numUnreadMsgsChanged( folder() );
00808     else
00809       mChanged = true;
00810     Q_UINT32 serNum = kmkernel->msgDict()->getMsgSerNum(folder(), idx);
00811     emit msgChanged( folder(), serNum, deltaUnread );
00812   }
00813 }
00814 
00815 //-----------------------------------------------------------------------------
00816 void FolderStorage::headerOfMsgChanged(const KMMsgBase* aMsg, int idx)
00817 {
00818   if (idx < 0)
00819     idx = aMsg->parent()->find( aMsg );
00820   if (idx >= 0 && !mQuiet)
00821     emit msgHeaderChanged(folder(), idx);
00822   else
00823     mChanged = true;
00824 }
00825 
00826 //-----------------------------------------------------------------------------
00827 void FolderStorage::readConfig()
00828 {
00829   //kdDebug(5006)<<"#### READING CONFIG  = "<< name() <<endl;
00830   KConfig* config = KMKernel::config();
00831   KConfigGroupSaver saver(config, "Folder-" + folder()->idString());
00832   if (mUnreadMsgs == -1)
00833     mUnreadMsgs = config->readNumEntry("UnreadMsgs", -1);
00834   if (mTotalMsgs == -1)
00835     mTotalMsgs = config->readNumEntry("TotalMsgs", -1);
00836   mCompactable = config->readBoolEntry("Compactable", TRUE);
00837 
00838   int type = config->readNumEntry( "ContentsType", 0 );
00839   if ( type < 0 || type > KMail::ContentsTypeLast ) type = 0;
00840   setContentsType( static_cast<KMail::FolderContentsType>( type ) );
00841 
00842   if( folder() ) folder()->readConfig( config );
00843 }
00844 
00845 //-----------------------------------------------------------------------------
00846 void FolderStorage::writeConfig()
00847 {
00848   KConfig* config = KMKernel::config();
00849   KConfigGroupSaver saver(config, "Folder-" + folder()->idString());
00850   config->writeEntry("UnreadMsgs", mGuessedUnreadMsgs == -1 ? mUnreadMsgs : -1);
00851   config->writeEntry("TotalMsgs", mTotalMsgs);
00852   config->writeEntry("Compactable", mCompactable);
00853   config->writeEntry("ContentsType", mContentsType);
00854 
00855   // Write the KMFolder parts
00856   if( folder() ) folder()->writeConfig( config );
00857 
00858   GlobalSettings::self()->requestSync();
00859 }
00860 
00861 //-----------------------------------------------------------------------------
00862 void FolderStorage::correctUnreadMsgsCount()
00863 {
00864   open();
00865   close();
00866   emit numUnreadMsgsChanged( folder() );
00867 }
00868 
00869 //-----------------------------------------------------------------------------
00870 void FolderStorage::fillMsgDict(KMMsgDict *dict)
00871 {
00872   fillDictFromIndex(dict);
00873 }
00874 
00875 //-----------------------------------------------------------------------------
00876 int FolderStorage::writeMsgDict(KMMsgDict *dict)
00877 {
00878   int ret = 0;
00879   if (!dict)
00880     dict = kmkernel->msgDict();
00881   if (dict)
00882     ret = dict->writeFolderIds(folder());
00883   return ret;
00884 }
00885 
00886 //-----------------------------------------------------------------------------
00887 int FolderStorage::touchMsgDict()
00888 {
00889   int ret = 0;
00890   KMMsgDict *dict = kmkernel->msgDict();
00891   if (dict)
00892     ret = dict->touchFolderIds(folder());
00893   return ret;
00894 }
00895 
00896 //-----------------------------------------------------------------------------
00897 int FolderStorage::appendtoMsgDict(int idx)
00898 {
00899   int ret = 0;
00900   KMMsgDict *dict = kmkernel->msgDict();
00901   if (dict) {
00902     if (count() == 1) {
00903       ret = dict->writeFolderIds(folder());
00904     } else {
00905       ret = dict->appendtoFolderIds(folder(), idx);
00906     }
00907   }
00908   return ret;
00909 }
00910 
00911 //-----------------------------------------------------------------------------
00912 void FolderStorage::setStatus(int idx, KMMsgStatus status, bool toggle)
00913 {
00914   KMMsgBase *msg = getMsgBase(idx);
00915   if ( msg ) {
00916     if (toggle)
00917       msg->toggleStatus(status, idx);
00918     else
00919       msg->setStatus(status, idx);
00920   }
00921 }
00922 
00923 void FolderStorage::setRDict(KMMsgDictREntry *rentry) {
00924   if (rentry == mRDict)
00925     return;
00926   KMMsgDict::deleteRentry(mRDict);
00927   mRDict = rentry;
00928 }
00929 
00930 //-----------------------------------------------------------------------------
00931 void FolderStorage::setStatus(QValueList<int>& ids, KMMsgStatus status, bool toggle)
00932 {
00933   for ( QValueList<int>::Iterator it = ids.begin(); it != ids.end(); ++it )
00934   {
00935     FolderStorage::setStatus(*it, status, toggle);
00936   }
00937 }
00938 
00939 void FolderStorage::ignoreJobsForMessage( KMMessage *msg )
00940 {
00941   if ( !msg || msg->transferInProgress() )
00942     return;
00943 
00944   QPtrListIterator<FolderJob> it( mJobList );
00945   while ( it.current() )
00946   {
00947     //FIXME: the questions is : should we iterate through all
00948     //messages in jobs? I don't think so, because it would
00949     //mean canceling the jobs that work with other messages
00950     if ( it.current()->msgList().first() == msg )
00951     {
00952       FolderJob* job = it.current();
00953       mJobList.remove( job );
00954       delete job;
00955     } else
00956       ++it;
00957   }
00958 }
00959 
00960 //-----------------------------------------------------------------------------
00961 void FolderStorage::removeJobs()
00962 {
00963   mJobList.setAutoDelete( true );
00964   mJobList.clear();
00965   mJobList.setAutoDelete( false );
00966 }
00967 
00968 //-----------------------------------------------------------------------------
00969 size_t FolderStorage::crlf2lf( char* str, const size_t strLen )
00970 {
00971   if ( !str || strLen == 0 ) return 0;
00972 
00973   const char* source = str;
00974   const char* sourceEnd = source + strLen;
00975 
00976   // search the first occurrence of "\r\n"
00977   for ( ; source < sourceEnd - 1; ++source ) {
00978     if ( *source == '\r' && *( source + 1 ) == '\n' )
00979       break;
00980   }
00981 
00982   if ( source == sourceEnd - 1 ) {
00983     // no "\r\n" found
00984     return strLen;
00985   }
00986 
00987   // replace all occurrences of "\r\n" with "\n" (in place)
00988   char* target = const_cast<char*>( source ); // target points to '\r'
00989   ++source; // source points to '\n'
00990   for ( ; source < sourceEnd; ++source ) {
00991     if ( *source != '\r' || *( source + 1 ) != '\n' )
00992       *target++ = *source;
00993   }
00994   *target = '\0'; // terminate result
00995   return target - str;
00996 }
00997 
00998 //-----------------------------------------------------------------------------
00999 void FolderStorage::updateChildrenState()
01000 {
01001   if ( folder() && folder()->child() )
01002   {
01003     if ( kmkernel->folderMgr()->folderCount( folder()->child() ) > 0 )
01004       setHasChildren( HasChildren );
01005     else
01006       setHasChildren( HasNoChildren );
01007   }
01008 }
01009 
01010 //-----------------------------------------------------------------------------
01011 void FolderStorage::setNoChildren( bool aNoChildren )
01012 {
01013   mNoChildren = aNoChildren;
01014   if ( aNoChildren )
01015     setHasChildren( HasNoChildren );
01016 }
01017 
01018 //-----------------------------------------------------------------------------
01019 void FolderStorage::setContentsType( KMail::FolderContentsType type, bool quiet )
01020 {
01021   if ( type != mContentsType ) {
01022     mContentsType = type;
01023     if ( !quiet )
01024       emit contentsTypeChanged( type );
01025   }
01026 }
01027 
01028 #include "folderstorage.moc"
KDE Logo
This file is part of the documentation for kmail Library Version 3.3.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Thu Aug 23 18:21:11 2007 by doxygen 1.4.2 written by Dimitri van Heesch, © 1997-2003