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