kmail Library API Documentation

kmfolderimap.cpp

00001 
00023 #ifdef HAVE_CONFIG_H
00024 #include <config.h>
00025 #endif
00026 
00027 #include "kmfolderimap.h"
00028 #include "kmfoldermbox.h"
00029 #include "kmfoldertree.h"
00030 #include "undostack.h"
00031 #include "kmfoldermgr.h"
00032 #include "imapjob.h"
00033 using KMail::ImapJob;
00034 #include "attachmentstrategy.h"
00035 using KMail::AttachmentStrategy;
00036 #include "progressmanager.h"
00037 using KPIM::ProgressItem;
00038 using KPIM::ProgressManager;
00039 #include "listjob.h"
00040 using KMail::ListJob;
00041 
00042 #include <kdebug.h>
00043 #include <kio/scheduler.h>
00044 #include <kconfig.h>
00045 
00046 #include <qbuffer.h>
00047 #include <qtextcodec.h>
00048 
00049 #include <assert.h>
00050 
00051 KMFolderImap::KMFolderImap(KMFolder* folder, const char* aName)
00052   : KMFolderMbox(folder, aName)
00053 {
00054   mContentState = imapNoInformation;
00055   mSubfolderState = imapNoInformation;
00056   mAccount = 0;
00057   mIsSelected = FALSE;
00058   mLastUid = 0;
00059   mCheckFlags = TRUE;
00060   mCheckMail = TRUE;
00061   mCheckingValidity = FALSE;
00062   mUserRights = 0;
00063   mAlreadyRemoved = false;
00064   mHasChildren = ChildrenUnknown;
00065   mMailCheckProgressItem = 0;
00066   mListDirProgressItem = 0;
00067 
00068   connect (this, SIGNAL( folderComplete( KMFolderImap*, bool ) ),
00069            this, SLOT( slotCompleteMailCheckProgress()) );
00070 }
00071 
00072 KMFolderImap::~KMFolderImap()
00073 {
00074   if (mAccount) {
00075     mAccount->removeSlaveJobsForFolder( folder() );
00076     /* Now that we've removed ourselves from the accounts jobs map, kill all
00077        ongoing operations and reset mailcheck if we were deleted during an
00078        ongoing mailcheck of our account. Not very gracefull, but safe, and the
00079        only way I can see to reset the account state cleanly. */
00080     if ( mAccount->checkingMail( folder() ) ) {
00081        mAccount->killAllJobs();
00082     }
00083   }
00084   writeConfig();
00085   if (kmkernel->undoStack()) kmkernel->undoStack()->folderDestroyed( folder() );
00086   mMetaDataMap.setAutoDelete( true );
00087   mMetaDataMap.clear();
00088 }
00089 
00090 
00091 //-----------------------------------------------------------------------------
00092 void KMFolderImap::close(bool aForced)
00093 {
00094   if (mOpenCount <= 0 ) return;
00095   if (mOpenCount > 0) mOpenCount--;
00096   if (mOpenCount > 0 && !aForced) return;
00097   // FIXME is this still needed?
00098   if (mAccount)
00099     mAccount->ignoreJobsForFolder( folder() );
00100   int idx = count();
00101   while (--idx >= 0) {
00102     if ( mMsgList[idx]->isMessage() ) {
00103       KMMessage *msg = static_cast<KMMessage*>(mMsgList[idx]);
00104       if (msg->transferInProgress())
00105           msg->setTransferInProgress( false );
00106     }
00107   }
00108   // The inherited close will decrement again, so we have to adjust.
00109   mOpenCount++;
00110   KMFolderMbox::close(aForced);
00111 }
00112 
00113 KMFolder* KMFolderImap::trashFolder() const
00114 {
00115   QString trashStr = account()->trash();
00116   return kmkernel->imapFolderMgr()->findIdString( trashStr );
00117 }
00118 
00119 //-----------------------------------------------------------------------------
00120 KMMessage* KMFolderImap::getMsg(int idx)
00121 {
00122   if(!(idx >= 0 && idx <= count()))
00123     return 0;
00124 
00125   KMMsgBase* mb = getMsgBase(idx);
00126   if (!mb) return 0;
00127   if (mb->isMessage())
00128   {
00129     return ((KMMessage*)mb);
00130   } else {
00131     KMMessage* msg = FolderStorage::getMsg( idx );
00132     if ( msg ) // set it incomplete as the msg was not transferred from the server
00133       msg->setComplete( false );
00134     return msg;
00135   }
00136 }
00137 
00138 //-----------------------------------------------------------------------------
00139 void KMFolderImap::setAccount(KMAcctImap *aAccount)
00140 {
00141   mAccount = aAccount;
00142   if( !folder() || !folder()->child() ) return;
00143   KMFolderNode* node;
00144   for (node = folder()->child()->first(); node;
00145        node = folder()->child()->next())
00146   {
00147     if (!node->isDir())
00148       static_cast<KMFolderImap*>(static_cast<KMFolder*>(node)->storage())->setAccount(aAccount);
00149   }
00150 }
00151 
00152 //-----------------------------------------------------------------------------
00153 void KMFolderImap::readConfig()
00154 {
00155   KConfig* config = KMKernel::config();
00156   KConfigGroupSaver saver(config, "Folder-" + folder()->idString());
00157   mCheckMail = config->readBoolEntry("checkmail", true);
00158 
00159   mUidValidity = config->readEntry("UidValidity");
00160   if (mImapPath.isEmpty()) mImapPath = config->readEntry("ImapPath");
00161   if (QString(name()).upper() == "INBOX" && mImapPath == "/INBOX/")
00162   {
00163     folder()->setSystemFolder( true );
00164     folder()->setLabel( i18n("inbox") );
00165   }
00166   mNoContent = config->readBoolEntry("NoContent", FALSE);
00167   mReadOnly = config->readBoolEntry("ReadOnly", FALSE);
00168 
00169   KMFolderMbox::readConfig();
00170 }
00171 
00172 //-----------------------------------------------------------------------------
00173 void KMFolderImap::writeConfig()
00174 {
00175   KConfig* config = KMKernel::config();
00176   KConfigGroupSaver saver(config, "Folder-" + folder()->idString());
00177   config->writeEntry("checkmail", mCheckMail);
00178   config->writeEntry("UidValidity", mUidValidity);
00179   config->writeEntry("ImapPath", mImapPath);
00180   config->writeEntry("NoContent", mNoContent);
00181   config->writeEntry("ReadOnly", mReadOnly);
00182   KMFolderMbox::writeConfig();
00183 }
00184 
00185 //-----------------------------------------------------------------------------
00186 void KMFolderImap::remove()
00187 {
00188   if ( mAlreadyRemoved || !mAccount )
00189   {
00190     // override
00191     FolderStorage::remove();
00192     return;
00193   }
00194   KURL url = mAccount->getUrl();
00195   url.setPath(imapPath());
00196   if ( mAccount->makeConnection() == ImapAccountBase::Error )
00197   {
00198     emit removed(folder(), false);
00199     return;
00200   }
00201   KIO::SimpleJob *job = KIO::file_delete(url, FALSE);
00202   KIO::Scheduler::assignJobToSlave(mAccount->slave(), job);
00203   ImapAccountBase::jobData jd(url.url());
00204   jd.progressItem = ProgressManager::createProgressItem(
00205                       "ImapFolderRemove" + ProgressManager::getUniqueID(),
00206                       "Removing folder",
00207                       "URL: " + folder()->prettyURL(),
00208                       false,
00209                       mAccount->useSSL() || mAccount->useTLS() );
00210   mAccount->insertJob(job, jd);
00211   connect(job, SIGNAL(result(KIO::Job *)),
00212           this, SLOT(slotRemoveFolderResult(KIO::Job *)));
00213 }
00214 
00215 //-----------------------------------------------------------------------------
00216 void KMFolderImap::slotRemoveFolderResult(KIO::Job *job)
00217 {
00218   ImapAccountBase::JobIterator it = mAccount->findJob(job);
00219   if ( it == mAccount->jobsEnd() ) return;
00220   if (job->error())
00221   {
00222     mAccount->handleJobError( job, i18n("Error while removing a folder.") );
00223     emit removed(folder(), false);
00224   } else {
00225     mAccount->removeJob(it);
00226     FolderStorage::remove();
00227   }
00228 
00229 }
00230 
00231 //-----------------------------------------------------------------------------
00232 void KMFolderImap::removeMsg(int idx, bool quiet)
00233 {
00234   if (idx < 0)
00235     return;
00236 
00237   if (!quiet)
00238   {
00239     KMMessage *msg = getMsg(idx);
00240     deleteMessage(msg);
00241   }
00242 
00243   mLastUid = 0;
00244   KMFolderMbox::removeMsg(idx);
00245 }
00246 
00247 void KMFolderImap::removeMsg( const QPtrList<KMMessage>& msgList, bool quiet )
00248 {
00249   if ( msgList.isEmpty() ) return;
00250   if (!quiet)
00251     deleteMessage(msgList);
00252 
00253   mLastUid = 0;
00254 
00255   /* Remove the messages from the local store as well.
00256      We don't call KMFolderInherited::removeMsg(QPtrList<KMMessage>) but
00257      iterate ourselves, as that would call KMFolderImap::removeMsg(int)
00258      and not the one from the store we want to be used. */
00259 
00260   QPtrListIterator<KMMessage> it( msgList );
00261   KMMessage *msg;
00262   while ( (msg = it.current()) != 0 ) {
00263     ++it;
00264     int idx = find(msg);
00265     assert( idx != -1);
00266     // ATTENTION port me to maildir
00267     KMFolderMbox::removeMsg(idx, quiet);
00268   }
00269 }
00270 
00271 //-----------------------------------------------------------------------------
00272 int KMFolderImap::rename( const QString& newName, KMFolderDir */*aParent*/ )
00273 {
00274   if ( newName == name() )
00275     return 0;
00276 
00277   QString path = imapPath();
00278   if ( path == "/INBOX/" )
00279       return 0;
00280   path.replace( name(), newName );
00281   KURL src( mAccount->getUrl() );
00282   src.setPath( imapPath() );
00283   KURL dst( mAccount->getUrl() );
00284   dst.setPath( path );
00285   // hack to transport the new name
00286   ImapAccountBase::jobData jd;
00287   jd.path = newName;
00288   KIO::SimpleJob *job = KIO::rename( src, dst, true );
00289   kdDebug(5006)<< "KMFolderImap::rename - " << src.prettyURL()
00290            << " |=> " << dst.prettyURL()
00291            << endl;
00292   mAccount->insertJob( job, jd );
00293   KIO::Scheduler::assignJobToSlave( mAccount->slave(), job );
00294   connect( job, SIGNAL(result(KIO::Job*)),
00295            SLOT(slotRenameResult(KIO::Job*)) );
00296   setImapPath( path );
00297   return 0;
00298 }
00299 
00300 //-----------------------------------------------------------------------------
00301 void KMFolderImap::slotRenameResult( KIO::Job *job )
00302 {
00303   ImapAccountBase::JobIterator it = mAccount->findJob( job );
00304   if ( it == mAccount->jobsEnd() ) return;
00305   KIO::SimpleJob* sj = static_cast<KIO::SimpleJob*>(job);
00306   if ( job->error() ) {
00307     // rollback
00308     setImapPath( sj->url().path() );
00309     mAccount->handleJobError( job, i18n("Error while renaming a folder.") );
00310     return;
00311   }
00312   // unsubscribe old (we don't want ghosts)
00313   mAccount->changeSubscription( false, sj->url().path() );
00314   // subscribe new
00315   mAccount->changeSubscription( true, imapPath() );
00316   // ATTENTION port me to maildir
00317   KMFolderMbox::rename( (*it).path );
00318   mAccount->removeJob(it);
00319   kmkernel->folderMgr()->contentsChanged();
00320 }
00321 
00322 //-----------------------------------------------------------------------------
00323 void KMFolderImap::addMsgQuiet(KMMessage* aMsg)
00324 {
00325   KMFolder *aFolder = aMsg->parent();
00326   Q_UINT32 serNum = 0;
00327   aMsg->setTransferInProgress( false );
00328   if (aFolder) {
00329     serNum = aMsg->getMsgSerNum();
00330     kmkernel->undoStack()->pushSingleAction( serNum, aFolder, folder() );
00331     int idx = aFolder->find( aMsg );
00332     assert( idx != -1 );
00333     aFolder->take( idx );
00334   }
00335   // Remember the status, so it can be transfered to the new message.
00336   mMetaDataMap.insert(aMsg->msgIdMD5(), new KMMsgMetaData(aMsg->status(), serNum));
00337 
00338   delete aMsg;
00339   aMsg = 0;
00340   getFolder();
00341 }
00342 
00343 //-----------------------------------------------------------------------------
00344 void KMFolderImap::addMsgQuiet(QPtrList<KMMessage> msgList)
00345 {
00346   KMFolder *aFolder = msgList.first()->parent();
00347   Q_UINT32 serNum = 0;
00348   if (aFolder) serNum = msgList.first()->getMsgSerNum();
00349   int undoId = -1;
00350   for ( KMMessage* msg = msgList.first(); msg; msg = msgList.next() )
00351   {
00352     if ( undoId == -1 )
00353       undoId = kmkernel->undoStack()->newUndoAction( aFolder, folder() );
00354     kmkernel->undoStack()->addMsgToAction( undoId, msg->getMsgSerNum() );
00355     // Remember the status, so it can be transfered to the new message.
00356     mMetaDataMap.insert(msg->msgIdMD5(), new KMMsgMetaData(msg->status(), serNum));
00357     msg->setTransferInProgress( false );
00358   }
00359   if (aFolder) aFolder->take(msgList);
00360   msgList.setAutoDelete(true);
00361   msgList.clear();
00362   getFolder();
00363 }
00364 
00365 //-----------------------------------------------------------------------------
00366 int KMFolderImap::addMsg(KMMessage* aMsg, int* aIndex_ret)
00367 {
00368   QPtrList<KMMessage> list; list.append(aMsg);
00369   return addMsg(list, aIndex_ret);
00370 }
00371 
00372 int KMFolderImap::addMsg(QPtrList<KMMessage>& msgList, int* aIndex_ret)
00373 {
00374   KMMessage *aMsg = msgList.getFirst();
00375   KMFolder *msgParent = aMsg->parent();
00376 
00377   ImapJob *imapJob = 0;
00378   if (msgParent)
00379   {
00380     if (msgParent->folderType() == KMFolderTypeImap)
00381     {
00382       if (static_cast<KMFolderImap*>(msgParent->storage())->account() == account())
00383       {
00384         // make sure the messages won't be deleted while we work with them
00385         for ( KMMessage* msg = msgList.first(); msg; msg = msgList.next() )
00386           msg->setTransferInProgress(true);
00387 
00388         if (folder() == msgParent)
00389         {
00390           // transfer the whole message, e.g. a draft-message is canceled and re-added to the drafts-folder
00391           for ( KMMessage* msg = msgList.first(); msg; msg = msgList.next() )
00392           {
00393             if (!msg->isComplete())
00394             {
00395               int idx = msgParent->find(msg);
00396               assert(idx != -1);
00397               msg = msgParent->getMsg(idx);
00398             }
00399             imapJob = new ImapJob(msg, ImapJob::tPutMessage, this);
00400             connect(imapJob, SIGNAL(messageStored(KMMessage*)),
00401                      SLOT(addMsgQuiet(KMMessage*)));
00402             imapJob->start();
00403           }
00404 
00405         } else {
00406 
00407           // get the messages and the uids
00408           QValueList<ulong> uids;
00409           getUids(msgList, uids);
00410 
00411           // get the sets (do not sort the uids)
00412           QStringList sets = makeSets(uids, false);
00413 
00414           for ( QStringList::Iterator it = sets.begin(); it != sets.end(); ++it )
00415           {
00416             // we need the messages that belong to the current set to pass them to the ImapJob
00417             QPtrList<KMMessage> temp_msgs = splitMessageList(*it, msgList);
00418             if ( temp_msgs.isEmpty() ) kdDebug(5006) << "Wow! KMFolderImap::splitMessageList() returned an empty list!" << endl;
00419             imapJob = new ImapJob(temp_msgs, *it, ImapJob::tMoveMessage, this);
00420             connect(imapJob, SIGNAL(messageCopied(QPtrList<KMMessage>)),
00421                 SLOT(addMsgQuiet(QPtrList<KMMessage>)));
00422             imapJob->start();
00423           }
00424         }
00425         if (aIndex_ret) *aIndex_ret = -1;
00426         return 0;
00427       }
00428       else
00429       {
00430         // different account, check if messages can be added
00431         QPtrListIterator<KMMessage> it( msgList );
00432         KMMessage *msg;
00433         while ( (msg = it.current()) != 0 )
00434         {
00435           ++it;
00436           if (!canAddMsgNow(msg, aIndex_ret))
00437             msgList.remove(msg);
00438           else {
00439             if (!msg->transferInProgress())
00440               msg->setTransferInProgress(true);
00441           }
00442         }
00443       }
00444     } // if imap
00445   }
00446 
00447   for ( KMMessage* msg = msgList.first(); msg; msg = msgList.next() )
00448   {
00449     // transfer from local folders or other accounts
00450     if (msgParent && !msg->isMessage())
00451     {
00452       int idx = msgParent->find(msg);
00453       assert(idx != -1);
00454       msg = msgParent->getMsg(idx);
00455     }
00456     if (!msg->transferInProgress())
00457       msg->setTransferInProgress(true);
00458     imapJob = new ImapJob(msg, ImapJob::tPutMessage, this);
00459     connect(imapJob, SIGNAL(messageStored(KMMessage*)),
00460             SLOT(addMsgQuiet(KMMessage*)));
00461     imapJob->start();
00462   }
00463 
00464   if (aIndex_ret) *aIndex_ret = -1;
00465   return 0;
00466 }
00467 
00468 //-----------------------------------------------------------------------------
00469 void KMFolderImap::copyMsg(QPtrList<KMMessage>& msgList)
00470 {
00471   for (KMMessage *msg = msgList.first(); msg; msg = msgList.next()) {
00472     // Remember the status, so it can be transfered to the new message.
00473     mMetaDataMap.insert(msg->msgIdMD5(), new KMMsgMetaData(msg->status()));
00474   }
00475   QValueList<ulong> uids;
00476   getUids(msgList, uids);
00477   QStringList sets = makeSets(uids, false);
00478   for ( QStringList::Iterator it = sets.begin(); it != sets.end(); ++it )
00479   {
00480     // we need the messages that belong to the current set to pass them to the ImapJob
00481     QPtrList<KMMessage> temp_msgs = splitMessageList(*it, msgList);
00482 
00483     ImapJob *job = new ImapJob(temp_msgs, *it, ImapJob::tCopyMessage, this);
00484     job->start();
00485   }
00486 }
00487 
00488 //-----------------------------------------------------------------------------
00489 QPtrList<KMMessage> KMFolderImap::splitMessageList(const QString& set,
00490                                                    QPtrList<KMMessage>& msgList)
00491 {
00492   int lastcomma = set.findRev(",");
00493   int lastdub = set.findRev(":");
00494   int last = 0;
00495   if (lastdub > lastcomma) last = lastdub;
00496   else last = lastcomma;
00497   last++;
00498   if (last < 0) last = set.length();
00499   // the last uid of the current set
00500   const QString last_uid = set.right(set.length() - last);
00501   QPtrList<KMMessage> temp_msgs;
00502   QString uid;
00503   if (!last_uid.isEmpty())
00504   {
00505     QPtrListIterator<KMMessage> it( msgList );
00506     KMMessage* msg = 0;
00507     while ( (msg = it.current()) != 0 )
00508     {
00509       // append the msg to the new list and delete it from the old
00510       temp_msgs.append(msg);
00511       uid.setNum( msg->UID() );
00512       // remove modifies the current
00513       msgList.remove(msg);
00514       if (uid == last_uid) break;
00515     }
00516   }
00517   else
00518   {
00519     // probably only one element
00520     temp_msgs = msgList;
00521   }
00522 
00523   return temp_msgs;
00524 }
00525 
00526 //-----------------------------------------------------------------------------
00527 KMMessage* KMFolderImap::take(int idx)
00528 {
00529   KMMsgBase* mb(mMsgList[idx]);
00530   if (!mb) return 0;
00531   if (!mb->isMessage()) readMsg(idx);
00532 
00533   KMMessage *msg = static_cast<KMMessage*>(mb);
00534   deleteMessage(msg);
00535 
00536   mLastUid = 0;
00537   return KMFolderMbox::take(idx);
00538 }
00539 
00540 void KMFolderImap::take(QPtrList<KMMessage> msgList)
00541 {
00542   deleteMessage(msgList);
00543 
00544   mLastUid = 0;
00545   KMFolderMbox::take(msgList);
00546 }
00547 
00548 //-----------------------------------------------------------------------------
00549 bool KMFolderImap::listDirectory(bool secondStep)
00550 {
00551   if ( !mAccount ||
00552        ( mAccount && mAccount->makeConnection() == ImapAccountBase::Error ) )
00553   {
00554     kdDebug(5006) << "KMFolderImap::listDirectory - got no connection" << endl;
00555     return false;
00556   }
00557 
00558   // reset
00559   if ( this == mAccount->rootFolder() )
00560   {
00561     mAccount->setHasInbox( false );
00562     // recursive
00563     setSubfolderState( imapNoInformation );
00564   }
00565   mSubfolderState = imapInProgress;
00566 
00567   // get the folders
00568   ImapAccountBase::ListType type = ImapAccountBase::List;
00569   if ( mAccount->onlySubscribedFolders() )
00570     type = ImapAccountBase::ListSubscribed;
00571   ListJob* job = new ListJob( this, mAccount, type, secondStep,
00572       false, mAccount->hasInbox(), QString::null, account()->listDirProgressItem() );
00573   job->setHonorLocalSubscription( true );
00574   connect( job, SIGNAL(receivedFolders(const QStringList&, const QStringList&,
00575           const QStringList&, const QStringList&, const ImapAccountBase::jobData&)),
00576       this, SLOT(slotListResult(const QStringList&, const QStringList&,
00577           const QStringList&, const QStringList&, const ImapAccountBase::jobData&)));
00578   job->start();
00579 
00580   return true;
00581 }
00582 
00583 
00584 //-----------------------------------------------------------------------------
00585 void KMFolderImap::slotListResult( const QStringList& subfolderNames_,
00586                                    const QStringList& subfolderPaths,
00587                                    const QStringList& subfolderMimeTypes,
00588                                    const QStringList& subfolderAttributes,
00589                                    const ImapAccountBase::jobData& jobData )
00590 {
00591   QStringList subfolderNames( subfolderNames_ ); // for the clear() below.
00592   mSubfolderState = imapFinished;
00593   bool it_inboxOnly = jobData.inboxOnly;
00594   bool createInbox = jobData.createInbox;
00595 //  kdDebug(5006) << name() << ": " << subfolderNames.join(",") << "; inboxOnly:" << it_inboxOnly
00596 //    << ", createinbox:" << createInbox << ", hasinbox:" << mAccount->hasInbox() << endl;
00597 
00598   // don't react on changes
00599   kmkernel->imapFolderMgr()->quiet(true);
00600   if (it_inboxOnly) {
00601     // list again only for the INBOX
00602     listDirectory(true);
00603   } else {
00604     if ( folder()->isSystemFolder() && mImapPath == "/INBOX/"
00605         && mAccount->prefix() == "/INBOX/" )
00606     {
00607       // do not create folders under INBOX when we have an INBOX prefix
00608       createInbox = false;
00609       subfolderNames.clear();
00610     }
00611     folder()->createChildFolder();
00612     KMFolderImap *f = 0;
00613     KMFolderNode *node = folder()->child()->first();
00614     while (node)
00615     {
00616       // check if the folders still exist on the server
00617       if (!node->isDir() && (node->name().upper() != "INBOX" || !createInbox)
00618           && subfolderNames.findIndex(node->name()) == -1)
00619       {
00620         kdDebug(5006) << node->name() << " disappeared" << endl;
00621         // remove the folder without server round trip
00622         KMFolder* fld = static_cast<KMFolder*>(node);
00623         static_cast<KMFolderImap*>(fld->storage())->setAlreadyRemoved(true);
00624         kmkernel->imapFolderMgr()->remove(fld);
00625         node = folder()->child()->first();
00626       }
00627       else node = folder()->child()->next();
00628     }
00629     if ( createInbox )
00630     {
00631       // create the INBOX
00632       for (node = folder()->child()->first(); node;
00633            node = folder()->child()->next())
00634         if (!node->isDir() && node->name() == "INBOX") break;
00635       if (node) {
00636         f = static_cast<KMFolderImap*>(static_cast<KMFolder*>(node)->storage());
00637       } else {
00638         f = static_cast<KMFolderImap*>
00639           (folder()->child()->createFolder("INBOX", true)->storage());
00640         if ( !mAccount->listOnlyOpenFolders() ) // should be ok as a default
00641           f->setHasChildren( FolderStorage::HasNoChildren );
00642       }
00643       f->setAccount(mAccount);
00644       f->setImapPath("/INBOX/");
00645       f->folder()->setLabel(i18n("inbox"));
00646       for (uint i = 0; i < subfolderNames.count(); i++)
00647       {
00648         if ( subfolderNames[i] == "INBOX" &&
00649              subfolderPaths[i] == "/INBOX/" )
00650           f->setNoChildren( subfolderMimeTypes[i] == "message/digest" );
00651       }
00652       if (!node) f->close();
00653       // so we have an INBOX
00654       mAccount->setHasInbox( true );
00655       kmkernel->imapFolderMgr()->contentsChanged();
00656       if ( !mAccount->listOnlyOpenFolders() ) {
00657         f->listDirectory();
00658       }
00659     }
00660     for (uint i = 0; i < subfolderNames.count(); i++)
00661     {
00662       // create folders if necessary
00663       if (subfolderNames[i].upper() == "INBOX" &&
00664           subfolderPaths[i] == "/INBOX/" &&
00665           mAccount->hasInbox()) // do not create an additional inbox
00666         continue;
00667       for (node = folder()->child()->first(); node;
00668            node = folder()->child()->next())
00669         if (!node->isDir() && node->name() == subfolderNames[i]) break;
00670       if (node)
00671         f = static_cast<KMFolderImap*>(static_cast<KMFolder*>(node)->storage());
00672       else {
00673         KMFolder *newFolder = folder()->child()->createFolder(subfolderNames[i]);
00674         if ( newFolder ) {
00675           f = static_cast<KMFolderImap*> ( newFolder->storage() );
00676           if ( f ) {
00677             f->close();
00678           }
00679         }
00680         if ( !f ) {
00681           kdWarning(5006) << "can't create folder " << subfolderNames[i] << endl;
00682         }
00683       }
00684       if (f)
00685       {
00686         // update progress
00687         account()->listDirProgressItem()->incCompletedItems();
00688         account()->listDirProgressItem()->updateProgress();
00689         account()->listDirProgressItem()->setStatus( folder()->prettyURL() + i18n(" completed") );
00690         f->setAccount(mAccount);
00691         if ( f->hasChildren() == FolderStorage::ChildrenUnknown )
00692         {
00693           // this is for new folders
00694           kmkernel->imapFolderMgr()->contentsChanged();
00695         }
00696 
00697         // update children state
00698         if ( subfolderAttributes[i].find( "haschildren", 0, false ) != -1 )
00699         {
00700           f->setHasChildren( FolderStorage::HasChildren );
00701         } else if ( subfolderAttributes[i].find( "hasnochildren", 0, false ) != -1 )
00702         {
00703           f->setHasChildren( FolderStorage::HasNoChildren );
00704         } else
00705         {
00706           if ( mAccount->listOnlyOpenFolders() )
00707             f->setHasChildren( FolderStorage::ChildrenUnknown );
00708           else // we don't need to be expandable
00709             f->setHasChildren( FolderStorage::HasNoChildren );
00710         }
00711         f->setImapPath(subfolderPaths[i]);
00712         f->setNoContent(subfolderMimeTypes[i] == "inode/directory");
00713         f->setNoChildren(subfolderMimeTypes[i] == "message/digest");
00714         if ( mAccount->listOnlyOpenFolders() &&
00715              f->hasChildren() != FolderStorage::ChildrenUnknown )
00716         {
00717           // tell the tree our information changed
00718           kmkernel->imapFolderMgr()->contentsChanged();
00719         }
00720         if ( ( subfolderMimeTypes[i] == "message/directory" ||
00721                subfolderMimeTypes[i] == "inode/directory" ) &&
00722              !mAccount->listOnlyOpenFolders() )
00723         {
00724           f->listDirectory();
00725         }
00726       }
00727     } // for subfolders
00728   } // inbox_only
00729   // now others should react on the changes
00730   kmkernel->imapFolderMgr()->quiet(false);
00731   emit directoryListingFinished( this );
00732   account()->listDirProgressItem()->setComplete();
00733 }
00734 
00735 //-----------------------------------------------------------------------------
00736 void KMFolderImap::checkValidity()
00737 {
00738   if (!mAccount) {
00739     emit folderComplete(this, false);
00740     return;
00741   }
00742   KURL url = mAccount->getUrl();
00743   url.setPath(imapPath() + ";UID=0:0");
00744   kdDebug(5006) << "KMFolderImap::checkValidity of: " << imapPath() << endl;
00745 
00746   // Start with a clean slate
00747   disconnect( mAccount, SIGNAL( connectionResult(int, const QString&) ),
00748               this, SLOT( checkValidity() ) );
00749 
00750   KMAcctImap::ConnectionState connectionState = mAccount->makeConnection();
00751   if ( connectionState == ImapAccountBase::Error ) {
00752     kdDebug(5006) << "KMFolderImap::checkValidity - got no connection" << endl;
00753     emit folderComplete(this, FALSE);
00754     mContentState = imapNoInformation;
00755     return;
00756   } else if ( connectionState == ImapAccountBase::Connecting ) {
00757     // We'll wait for the connectionResult signal from the account. If it
00758     // errors, the above will catch it.
00759     kdDebug(5006) << "CheckValidity - waiting for connection" << endl;
00760     connect( mAccount, SIGNAL( connectionResult(int, const QString&) ),
00761         this, SLOT( checkValidity() ) );
00762     return;
00763   }
00764   // Only check once at a time.
00765   if (mCheckingValidity) {
00766     kdDebug(5006) << "KMFolderImap::checkValidity - already checking" << endl;
00767     return;
00768   }
00769   // otherwise we already are inside a mailcheck
00770   if ( !mMailCheckProgressItem ) {
00771     mMailCheckProgressItem = ProgressManager::createProgressItem(
00772               account()->mailCheckProgressItem(),
00773               "MailCheck" + folder()->prettyURL(),
00774               folder()->prettyURL(),
00775               i18n("checking"),
00776               false,
00777               account()->useSSL() || account()->useTLS() );
00778   } else {
00779     mMailCheckProgressItem->setProgress(0);
00780   }
00781   if ( account()->mailCheckProgressItem() ) {
00782     account()->mailCheckProgressItem()->setStatus( folder()->prettyURL() );
00783   }
00784   ImapAccountBase::jobData jd( url.url() );
00785   KIO::SimpleJob *job = KIO::get(url, FALSE, FALSE);
00786   KIO::Scheduler::assignJobToSlave(mAccount->slave(), job);
00787   mAccount->insertJob(job, jd);
00788   connect(job, SIGNAL(result(KIO::Job *)),
00789           SLOT(slotCheckValidityResult(KIO::Job *)));
00790   connect(job, SIGNAL(data(KIO::Job *, const QByteArray &)),
00791           SLOT(slotSimpleData(KIO::Job *, const QByteArray &)));
00792   // Only check once at a time.
00793   mCheckingValidity = true;
00794 }
00795 
00796 
00797 //-----------------------------------------------------------------------------
00798 ulong KMFolderImap::lastUid()
00799 {
00800   if (mLastUid) return mLastUid;
00801   open();
00802   if (count() > 0)
00803   {
00804     KMMsgBase * base = getMsgBase(count()-1);
00805     mLastUid = base->UID();
00806   }
00807   close();
00808   return mLastUid;
00809 }
00810 
00811 
00812 //-----------------------------------------------------------------------------
00813 void KMFolderImap::slotCheckValidityResult(KIO::Job * job)
00814 {
00815   kdDebug(5006) << "KMFolderImap::slotCheckValidityResult of: " << fileName() << endl;
00816   mCheckingValidity = false;
00817   ImapAccountBase::JobIterator it = mAccount->findJob(job);
00818   if ( it == mAccount->jobsEnd() ) return;
00819   if (job->error()) {
00820     mAccount->handleJobError( job, i18n("Error while querying the server status.") );
00821     mContentState = imapNoInformation;
00822     emit folderComplete(this, FALSE);
00823   } else {
00824     QCString cstr((*it).data.data(), (*it).data.size() + 1);
00825     int a = cstr.find("X-uidValidity: ");
00826     int b = cstr.find("\r\n", a);
00827     QString uidv;
00828     if ( (b - a - 15) >= 0 ) uidv = cstr.mid(a + 15, b - a - 15);
00829     a = cstr.find("X-Access: ");
00830     b = cstr.find("\r\n", a);
00831     QString access;
00832     if ( (b - a - 10) >= 0 ) access = cstr.mid(a + 10, b - a - 10);
00833     mReadOnly = access == "Read only";
00834     int c = (*it).cdata.find("\r\nX-Count:");
00835     int exists = -1;
00836     if ( c != -1 )
00837     {
00838       bool ok;
00839       exists = (*it).cdata.mid( c+10,
00840           (*it).cdata.find("\r\n", c+1) - c-10 ).toInt(&ok);
00841       if ( !ok ) exists = -1;
00842     }
00843     QString startUid;
00844     if (uidValidity() != uidv)
00845     {
00846       // uidValidity changed
00847       kdDebug(5006) << "KMFolderImap::slotCheckValidityResult uidValidty changed." << endl;
00848       mAccount->ignoreJobsForFolder( folder() );
00849       mLastUid = 0;
00850       uidmap.clear();
00851       setUidValidity(uidv);
00852     } else {
00853       if (!mCheckFlags)
00854         startUid = QString::number(lastUid() + 1);
00855     }
00856     mAccount->removeJob(it);
00857     if ( mMailCheckProgressItem )
00858     {
00859       if ( startUid.isEmpty() ) {
00860         // flags for all messages are loaded
00861         mMailCheckProgressItem->setTotalItems( exists );
00862       } else {
00863         // only an approximation but doesn't hurt
00864         int remain = exists - count();
00865         if ( remain < 0 ) remain = 1;
00866         mMailCheckProgressItem->setTotalItems( remain );
00867       }
00868       mMailCheckProgressItem->setCompletedItems( 0 );
00869     }
00870     reallyGetFolder(startUid);
00871   }
00872 }
00873 
00874 //-----------------------------------------------------------------------------
00875 void KMFolderImap::getAndCheckFolder(bool force)
00876 {
00877   if (mNoContent)
00878     return getFolder(force);
00879 
00880   if ( mAccount )
00881     mAccount->processNewMailSingleFolder( folder() );
00882   if (force) {
00883     // force an update
00884     mCheckFlags = TRUE;
00885   }
00886 }
00887 
00888 //-----------------------------------------------------------------------------
00889 void KMFolderImap::getFolder(bool force)
00890 {
00891   mGuessedUnreadMsgs = -1;
00892   if (mNoContent)
00893   {
00894     mContentState = imapFinished;
00895     emit folderComplete(this, true);
00896     return;
00897   }
00898   mContentState = imapInProgress;
00899   if (force) {
00900     // force an update
00901     mCheckFlags = TRUE;
00902   }
00903   checkValidity();
00904 }
00905 
00906 
00907 //-----------------------------------------------------------------------------
00908 void KMFolderImap::reallyGetFolder(const QString &startUid)
00909 {
00910   KURL url = mAccount->getUrl();
00911   if ( mAccount->makeConnection() != ImapAccountBase::Connected )
00912   {
00913     mContentState = imapNoInformation;
00914     emit folderComplete(this, FALSE);
00915     return;
00916   }
00917   quiet(true);
00918   if (startUid.isEmpty())
00919   {
00920     if ( mMailCheckProgressItem )
00921       mMailCheckProgressItem->setStatus( i18n("Retrieving message status") );
00922     url.setPath(imapPath() + ";SECTION=UID FLAGS");
00923     KIO::SimpleJob *job = KIO::listDir(url, FALSE);
00924     KIO::Scheduler::assignJobToSlave(mAccount->slave(), job);
00925     ImapAccountBase::jobData jd( url.url(), folder() );
00926     jd.cancellable = true;
00927     mAccount->insertJob(job, jd);
00928     connect(job, SIGNAL(result(KIO::Job *)),
00929             this, SLOT(slotListFolderResult(KIO::Job *)));
00930     connect(job, SIGNAL(entries(KIO::Job *, const KIO::UDSEntryList &)),
00931             this, SLOT(slotListFolderEntries(KIO::Job *,
00932             const KIO::UDSEntryList &)));
00933   } else {
00934     if ( mMailCheckProgressItem )
00935       mMailCheckProgressItem->setStatus( i18n("Retrieving messages") );
00936     url.setPath(imapPath() + ";UID=" + startUid
00937       + ":*;SECTION=ENVELOPE");
00938     KIO::SimpleJob *newJob = KIO::get(url, FALSE, FALSE);
00939     KIO::Scheduler::assignJobToSlave(mAccount->slave(), newJob);
00940     ImapAccountBase::jobData jd( url.url(), folder() );
00941     jd.cancellable = true;
00942     mAccount->insertJob(newJob, jd);
00943     connect(newJob, SIGNAL(result(KIO::Job *)),
00944             this, SLOT(slotGetLastMessagesResult(KIO::Job *)));
00945     connect(newJob, SIGNAL(data(KIO::Job *, const QByteArray &)),
00946             this, SLOT(slotGetMessagesData(KIO::Job *, const QByteArray &)));
00947   }
00948 }
00949 
00950 
00951 //-----------------------------------------------------------------------------
00952 void KMFolderImap::slotListFolderResult(KIO::Job * job)
00953 {
00954   ImapAccountBase::JobIterator it = mAccount->findJob(job);
00955   if ( it == mAccount->jobsEnd() ) return;
00956   QString uids;
00957   if (job->error())
00958   {
00959     mAccount->handleJobError( job,
00960         i18n("Error while listing the contents of the folder %1.").arg( label() ) );
00961     quiet( false );
00962     mContentState = imapNoInformation;
00963     emit folderComplete(this, FALSE);
00964     mAccount->removeJob(it);
00965     return;
00966   }
00967   mCheckFlags = FALSE;
00968   QStringList::Iterator uid;
00969   /*
00970     The code below does the following:
00971     - for each mail in the local store and each entry we got from the server,
00972       compare the local uid with the one from the server and update the status
00973       flags of the mails
00974     - for all mails that are not already locally present, start a job which
00975       gets the envelope of each
00976     - remove all locally present mails if the server does not list them anymore
00977   */
00978   if ( count() ) {
00979     int idx = 0, c, serverFlags;
00980     ulong mailUid, serverUid;
00981     uid = (*it).items.begin();
00982     while ( idx < count() && uid != (*it).items.end() ) {
00983       KMMsgBase *msgBase = getMsgBase( idx );
00984       mailUid = msgBase->UID();
00985       // parse the uid from the server and the flags out of the list from
00986       // the server. Format: 1234, 1
00987       c = (*uid).find(",");
00988       serverUid = (*uid).left( c ).toLong();
00989       serverFlags = (*uid).mid( c+1 ).toInt();
00990       if ( mailUid < serverUid ) {
00991         removeMsg( idx, TRUE );
00992       } else if ( mailUid == serverUid ) {
00993         // if this is a read only folder, ignore status updates from the server
00994         // since we can't write our status back our local version is what has to
00995         // be considered correct.
00996         if (!mReadOnly)
00997           flagsToStatus( msgBase, serverFlags, false );
00998         idx++;
00999         uid = (*it).items.remove(uid);
01000       }
01001       else break;  // happens only, if deleted mails reappear on the server
01002     }
01003     // remove all remaining entries in the local cache, they are no longer
01004     // present on the server
01005     while (idx < count()) removeMsg(idx, TRUE);
01006   }
01007   // strip the flags from the list of uids, so it can be reused
01008   for (uid = (*it).items.begin(); uid != (*it).items.end(); uid++)
01009     (*uid).truncate((*uid).find(","));
01010   ImapAccountBase::jobData jd( QString::null, (*it).parent );
01011   jd.total = (*it).items.count();
01012   if (jd.total == 0)
01013   {
01014     quiet(false);
01015     mContentState = imapFinished;
01016     emit folderComplete(this, TRUE);
01017     mAccount->removeJob(it);
01018     return;
01019   }
01020   if ( mMailCheckProgressItem )
01021   {
01022     // next step for the progressitem
01023     mMailCheckProgressItem->setProgress( 0 );
01024     mMailCheckProgressItem->setTotalItems( jd.total );
01025     mMailCheckProgressItem->updateProgress();
01026     mMailCheckProgressItem->setStatus( i18n("Retrieving messages") );
01027   }
01028 
01029   QStringList sets;
01030   uid = (*it).items.begin();
01031   if (jd.total == 1) sets.append(*uid + ":" + *uid);
01032   else sets = makeSets( (*it).items );
01033   mAccount->removeJob(it); // don't use *it below
01034 
01035   // Now kick off the getting of envelopes for the new mails in the folder
01036   for (QStringList::Iterator i = sets.begin(); i != sets.end(); ++i)
01037   {
01038     KURL url = mAccount->getUrl();
01039     url.setPath(imapPath() + ";UID=" + *i + ";SECTION=ENVELOPE");
01040     if ( mAccount->makeConnection() != ImapAccountBase::Connected )
01041     {
01042       quiet(false);
01043       emit folderComplete(this, FALSE);
01044       return;
01045     }
01046     KIO::SimpleJob *newJob = KIO::get(url, FALSE, FALSE);
01047     jd.url = url.url();
01048     KIO::Scheduler::assignJobToSlave(mAccount->slave(), newJob);
01049     mAccount->insertJob(newJob, jd);
01050     connect(newJob, SIGNAL(result(KIO::Job *)),
01051         this, (i == sets.at(sets.count() - 1))
01052         ? SLOT(slotGetLastMessagesResult(KIO::Job *))
01053         : SLOT(slotGetMessagesResult(KIO::Job *)));
01054     connect(newJob, SIGNAL(data(KIO::Job *, const QByteArray &)),
01055         this, SLOT(slotGetMessagesData(KIO::Job *, const QByteArray &)));
01056   }
01057 }
01058 
01059 
01060 //-----------------------------------------------------------------------------
01061 void KMFolderImap::slotListFolderEntries(KIO::Job * job,
01062   const KIO::UDSEntryList & uds)
01063 {
01064   ImapAccountBase::JobIterator it = mAccount->findJob(job);
01065   if ( it == mAccount->jobsEnd() ) return;
01066   QString mimeType, name;
01067   long int flags = 0;
01068   for (KIO::UDSEntryList::ConstIterator udsIt = uds.begin();
01069     udsIt != uds.end(); udsIt++)
01070   {
01071     for (KIO::UDSEntry::ConstIterator eIt = (*udsIt).begin();
01072       eIt != (*udsIt).end(); eIt++)
01073     {
01074       if ((*eIt).m_uds == KIO::UDS_NAME)
01075         name = (*eIt).m_str;
01076       else if ((*eIt).m_uds == KIO::UDS_MIME_TYPE)
01077         mimeType = (*eIt).m_str;
01078       else if ((*eIt).m_uds == KIO::UDS_ACCESS)
01079         flags = (*eIt).m_long;
01080     }
01081     if ((mimeType == "message/rfc822-imap" || mimeType == "message/rfc822") &&
01082         !(flags & 8)) {
01083       (*it).items.append(name + "," + QString::number(flags));
01084       if ( mMailCheckProgressItem ) {
01085         mMailCheckProgressItem->incCompletedItems();
01086         mMailCheckProgressItem->updateProgress();
01087       }
01088     }
01089   }
01090 }
01091 
01092 
01093 // debugging helper
01094 //X static QString flagsToString( int flags )
01095 //X {
01096 //X     QString str("(");
01097 //X     if ( flags & 4 ) {
01098 //X         str += "\\Flagged ";
01099 //X     }
01100 //X     if ( flags & 2 ) {
01101 //X         str += "\\Answered ";
01102 //X     }
01103 //X     if ( flags & 1 ) {
01104 //X         str += "\\Seen";
01105 //X     }
01106 //X     str += ")";
01107 //X     return str;
01108 //X }
01109 
01110 //-----------------------------------------------------------------------------
01111 void KMFolderImap::flagsToStatus(KMMsgBase *msg, int flags, bool newMsg)
01112 {
01113   const KMMsgStatus oldStatus = msg->status();
01114   // Toggle flags if they changed
01115   if ( ( (flags & 4) > 0 ) != ( (oldStatus & KMMsgStatusFlag) > 0 ) )
01116     msg->toggleStatus( KMMsgStatusFlag );
01117   if ( ( (flags & 2) > 0 ) != ( (oldStatus & KMMsgStatusReplied) > 0 ) )
01118     msg->toggleStatus( KMMsgStatusReplied );
01119 
01120   // if the SEEN flag is set, we are neither new nor unread
01121   if ( ( (flags & 1) > 0 ) ) {
01122       if ( oldStatus & KMMsgStatusNew || oldStatus & KMMsgStatusUnread ) {
01123         msg->setStatus( KMMsgStatusOld );
01124       }
01125   }
01126 
01127   // In case the message does not have the seen flag set, override our local
01128   // notion that it is read. Otherwise the count of unread messages and the
01129   // number of messages which actually show up as read can go out of sync.
01130   if (msg->isOfUnknownStatus() || !(flags&1) ) {
01131     if (newMsg) {
01132       if ( (oldStatus & KMMsgStatusNew) == 0 )
01133         msg->setStatus( KMMsgStatusNew );
01134     } else {
01135       if ( (oldStatus & KMMsgStatusUnread) == 0 )
01136         msg->setStatus( KMMsgStatusUnread );
01137     }
01138   }
01139 }
01140 
01141 
01142 //-----------------------------------------------------------------------------
01143 QString KMFolderImap::statusToFlags(KMMsgStatus status)
01144 {
01145   QString flags;
01146   if (status & KMMsgStatusDeleted)
01147     flags = "\\DELETED";
01148   else {
01149     if (status & KMMsgStatusOld || status & KMMsgStatusRead)
01150       flags = "\\SEEN ";
01151     if (status & KMMsgStatusReplied)
01152       flags += "\\ANSWERED ";
01153     if (status & KMMsgStatusFlag)
01154       flags += "\\FLAGGED";
01155   }
01156 
01157   return flags.simplifyWhiteSpace();
01158 }
01159 
01160 //-------------------------------------------------------------
01161 void
01162 KMFolderImap::ignoreJobsForMessage( KMMessage* msg )
01163 {
01164   if ( !msg || msg->transferInProgress() ||
01165        !msg->parent() || msg->parent()->folderType() != KMFolderTypeImap )
01166     return;
01167   KMAcctImap *account;
01168   if ( !(account = static_cast<KMFolderImap*>(msg->storage())->account()) )
01169     return;
01170 
01171   account->ignoreJobsForMessage( msg );
01172 }
01173 
01174 //-----------------------------------------------------------------------------
01175 void KMFolderImap::slotGetMessagesData(KIO::Job * job, const QByteArray & data)
01176 {
01177   if ( data.isEmpty() ) return; // optimization
01178   ImapAccountBase::JobIterator it = mAccount->findJob(job);
01179   if ( it == mAccount->jobsEnd() ) return;
01180   (*it).cdata += QCString(data, data.size() + 1);
01181   int pos = (*it).cdata.find("\r\n--IMAPDIGEST");
01182   if (pos > 0)
01183   {
01184     int p = (*it).cdata.find("\r\nX-uidValidity:");
01185     if (p != -1) setUidValidity((*it).cdata
01186       .mid(p + 17, (*it).cdata.find("\r\n", p+1) - p - 17));
01187     int c = (*it).cdata.find("\r\nX-Count:");
01188     if ( c != -1 )
01189     {
01190       bool ok;
01191       int exists = (*it).cdata.mid( c+10,
01192           (*it).cdata.find("\r\n", c+1) - c-10 ).toInt(&ok);
01193       if ( ok && exists < count() ) {
01194         kdDebug(5006) << "KMFolderImap::slotGetMessagesData - server has less messages (" <<
01195           exists << ") then folder (" << count() << "), so reload" << endl;
01196         reallyGetFolder( QString::null );
01197         (*it).cdata.remove(0, pos);
01198         return;
01199       } else if ( ok ) {
01200         int delta = exists - count();
01201         if ( mMailCheckProgressItem ) {
01202           mMailCheckProgressItem->setTotalItems( delta );
01203           mMailCheckProgressItem->setStatus( i18n("Retrieving message list") );
01204         }
01205       }
01206     }
01207     (*it).cdata.remove(0, pos);
01208   }
01209   pos = (*it).cdata.find("\r\n--IMAPDIGEST", 1);
01210   int flags;
01211   open();
01212   while (pos >= 0)
01213   {
01214     KMMessage *msg = new KMMessage;
01215     msg->setComplete(false);
01216     msg->setReadyToShow(false);
01217     msg->fromString((*it).cdata.mid(16, pos - 16));
01218     flags = msg->headerField("X-Flags").toInt();
01219     ulong uid = msg->UID();
01220     bool ok = true;
01221     if ( uid <= lastUid() )
01222     {
01223       // as some servers send the messages out of order
01224       // we have to check if the message really already exists
01225       int idx = 0;
01226       KMMsgBase *msg;
01227       while ( idx < count() )
01228       {
01229         msg = getMsgBase( idx );
01230         if ( msg && msg->UID() == uid )
01231         {
01232           ok = false; // exists, no need to create it
01233           break;
01234         }
01235         ++idx;
01236       }
01237     }
01238     // deleted flag
01239     if ( flags & 8 )
01240       ok = false;
01241     if ( !ok ) {
01242       delete msg;
01243       msg = 0;
01244     } else {
01245       if (uidmap.find(uid)) {
01246         // assign the sernum from the cache
01247         const ulong sernum = (ulong) uidmap[uid];
01248         msg->setMsgSerNum(sernum);
01249         // delete the entry
01250         uidmap.remove(uid);
01251       }
01252       KMFolderMbox::addMsg(msg, 0);
01253       // Transfer the status, if it is cached.
01254       QString id = msg->msgIdMD5();
01255       if ( mMetaDataMap.find( id ) ) {
01256         KMMsgMetaData *md =  mMetaDataMap[id];
01257         msg->setStatus( md->status() );
01258         if ( md->serNum() != 0 )
01259           msg->setMsgSerNum( md->serNum() );
01260         mMetaDataMap.remove( id );
01261         delete md;
01262       }
01263       // Merge with the flags from the server.
01264       flagsToStatus((KMMsgBase*)msg, flags);
01265       // set the correct size
01266       msg->setMsgSizeServer( msg->headerField("X-Length").toUInt() );
01267       msg->setUID(uid);
01268 
01269       if (count() > 1) unGetMsg(count() - 1);
01270       mLastUid = uid;
01271       if ( mMailCheckProgressItem ) {
01272         mMailCheckProgressItem->incCompletedItems();
01273         mMailCheckProgressItem->updateProgress();
01274       }
01275     }
01276     (*it).cdata.remove(0, pos);
01277     (*it).done++;
01278     pos = (*it).cdata.find("\r\n--IMAPDIGEST", 1);
01279   } // while
01280   close();
01281 }
01282 
01283 //-------------------------------------------------------------
01284 FolderJob*
01285 KMFolderImap::doCreateJob( KMMessage *msg, FolderJob::JobType jt,
01286                            KMFolder *folder, QString partSpecifier,
01287                            const AttachmentStrategy *as ) const
01288 {
01289   KMFolderImap* kmfi = folder? dynamic_cast<KMFolderImap*>(folder->storage()) : 0;
01290   if ( jt == FolderJob::tGetMessage && partSpecifier == "STRUCTURE" &&
01291        mAccount && mAccount->loadOnDemand() &&
01292        ( msg->msgSizeServer() > 5000 || msg->msgSizeServer() == 0 ) &&
01293        ( msg->signatureState() == KMMsgNotSigned ||
01294          msg->signatureState() == KMMsgSignatureStateUnknown ) &&
01295        ( msg->encryptionState() == KMMsgNotEncrypted ||
01296          msg->encryptionState() == KMMsgEncryptionStateUnknown ) )
01297   {
01298     // load-on-demand: retrieve the BODYSTRUCTURE and to speed things up also the headers
01299     // this is not activated for small or signed messages
01300     ImapJob *job = new ImapJob( msg, jt, kmfi, "HEADER" );
01301     job->start();
01302     ImapJob *job2 = new ImapJob( msg, jt, kmfi, "STRUCTURE", as );
01303     job2->start();
01304     job->setParentFolder( this );
01305     return job;
01306   } else {
01307     // download complete message or part (attachment)
01308     if ( partSpecifier == "STRUCTURE" ) // hide from outside
01309       partSpecifier = QString::null;
01310 
01311     ImapJob *job = new ImapJob( msg, jt, kmfi, partSpecifier );
01312     job->setParentFolder( this );
01313     return job;
01314   }
01315 }
01316 
01317 //-------------------------------------------------------------
01318 FolderJob*
01319 KMFolderImap::doCreateJob( QPtrList<KMMessage>& msgList, const QString& sets,
01320                            FolderJob::JobType jt, KMFolder *folder ) const
01321 {
01322   KMFolderImap* kmfi = dynamic_cast<KMFolderImap*>(folder->storage());
01323   ImapJob *job = new ImapJob( msgList, sets, jt, kmfi );
01324   job->setParentFolder( this );
01325   return job;
01326 }
01327 
01328 //-----------------------------------------------------------------------------
01329 void KMFolderImap::getMessagesResult(KIO::Job * job, bool lastSet)
01330 {
01331   ImapAccountBase::JobIterator it = mAccount->findJob(job);
01332   if ( it == mAccount->jobsEnd() ) return;
01333   if (job->error())
01334   {
01335     mAccount->handleJobError( job, i18n("Error while retrieving messages.") );
01336     mContentState = imapNoInformation;
01337     quiet( false );
01338     emit folderComplete(this, false);
01339   }
01340   else
01341   {
01342     if (lastSet)
01343     {
01344       mContentState = imapFinished;
01345       quiet(false);
01346       emit folderComplete(this, true);
01347     }
01348     mAccount->removeJob(it);
01349   }
01350 }
01351 
01352 
01353 //-----------------------------------------------------------------------------
01354 void KMFolderImap::slotGetLastMessagesResult(KIO::Job * job)
01355 {
01356   getMessagesResult(job, true);
01357 }
01358 
01359 
01360 //-----------------------------------------------------------------------------
01361 void KMFolderImap::slotGetMessagesResult(KIO::Job * job)
01362 {
01363   getMessagesResult(job, false);
01364 }
01365 
01366 
01367 //-----------------------------------------------------------------------------
01368 void KMFolderImap::createFolder(const QString &name)
01369 {
01370   if ( mAccount->makeConnection() == ImapAccountBase::Error ) {
01371     kdWarning(5006) << "KMFolderImap::createFolder - got no connection" << endl;
01372     return;
01373   } else if ( mAccount->makeConnection() == ImapAccountBase::Connecting ) {
01374     // We'll wait for the connectionResult signal from the account.
01375     kdDebug(5006) << "KMFolderImap::createFolder - waiting for connection" << endl;
01376 
01377     if ( mFoldersPendingCreation.isEmpty() ) {
01378       // first folder, connect
01379       connect( mAccount, SIGNAL( connectionResult(int, const QString&) ),
01380                this, SLOT( slotCreatePendingFolders() ) );
01381     }
01382     mFoldersPendingCreation << name;
01383     return;
01384   }
01385   KURL url = mAccount->getUrl();
01386   url.setPath(imapPath() + name);
01387 
01388   KIO::SimpleJob *job = KIO::mkdir(url);
01389   KIO::Scheduler::assignJobToSlave(mAccount->slave(), job);
01390   ImapAccountBase::jobData jd( url.url(), folder() );
01391   jd.items = name;
01392   mAccount->insertJob(job, jd);
01393   connect(job, SIGNAL(result(KIO::Job *)),
01394           this, SLOT(slotCreateFolderResult(KIO::Job *)));
01395 }
01396 
01397 
01398 //-----------------------------------------------------------------------------
01399 void KMFolderImap::slotCreateFolderResult(KIO::Job * job)
01400 {
01401   ImapAccountBase::JobIterator it = mAccount->findJob(job);
01402   if ( it == mAccount->jobsEnd() ) return;
01403   if (job->error())
01404   {
01405     if ( job->error() == KIO::ERR_COULD_NOT_MKDIR ) {
01406       // Creating a folder failed, remove it from the tree.
01407       mAccount->listDirectory( );
01408     }
01409     mAccount->handleJobError( job, i18n("Error while creating a folder.") );
01410   } else {
01411     listDirectory();
01412     mAccount->removeJob(job);
01413   }
01414 }
01415 
01416 
01417 //-----------------------------------------------------------------------------
01418 static QTextCodec *sUtf7Codec = 0;
01419 
01420 QTextCodec * KMFolderImap::utf7Codec()
01421 {
01422   if (!sUtf7Codec) sUtf7Codec = QTextCodec::codecForName("utf-7");
01423   return sUtf7Codec;
01424 }
01425 
01426 
01427 //-----------------------------------------------------------------------------
01428 QString KMFolderImap::encodeFileName(const QString &name)
01429 {
01430   QString result = utf7Codec()->fromUnicode(name);
01431   return KURL::encode_string_no_slash(result);
01432 }
01433 
01434 
01435 //-----------------------------------------------------------------------------
01436 QString KMFolderImap::decodeFileName(const QString &name)
01437 {
01438   QString result = KURL::decode_string(name);
01439   return utf7Codec()->toUnicode(result.latin1());
01440 }
01441 
01442 //-----------------------------------------------------------------------------
01443 bool KMFolderImap::autoExpunge()
01444 {
01445   if (mAccount)
01446     return mAccount->autoExpunge();
01447 
01448   return false;
01449 }
01450 
01451 
01452 //-----------------------------------------------------------------------------
01453 void KMFolderImap::slotSimpleData(KIO::Job * job, const QByteArray & data)
01454 {
01455   if ( data.isEmpty() ) return; // optimization
01456   ImapAccountBase::JobIterator it = mAccount->findJob(job);
01457   if ( it == mAccount->jobsEnd() ) return;
01458   QBuffer buff((*it).data);
01459   buff.open(IO_WriteOnly | IO_Append);
01460   buff.writeBlock(data.data(), data.size());
01461   buff.close();
01462 }
01463 
01464 //-----------------------------------------------------------------------------
01465 void KMFolderImap::deleteMessage(KMMessage * msg)
01466 {
01467   KURL url = mAccount->getUrl();
01468   KMFolderImap *msg_parent = static_cast<KMFolderImap*>(msg->storage());
01469   ulong uid = msg->UID();
01470   /* If the uid is empty the delete job below will nuke all mail in the
01471      folder, so we better safeguard against that. See ::expungeFolder, as
01472      to why. :( */
01473   if ( uid == 0 ) {
01474      kdDebug( 5006 ) << "KMFolderImap::deleteMessage: Attempt to delete "
01475                         "an empty UID. Aborting."  << endl;
01476      return;
01477   }
01478   url.setPath(msg_parent->imapPath() + ";UID=" + QString::number(uid) );
01479   if ( mAccount->makeConnection() != ImapAccountBase::Connected )
01480     return;
01481   KIO::SimpleJob *job = KIO::file_delete(url, FALSE);
01482   KIO::Scheduler::assignJobToSlave(mAccount->slave(), job);
01483   ImapAccountBase::jobData jd( url.url(), 0 );
01484   mAccount->insertJob(job, jd);
01485   connect(job, SIGNAL(result(KIO::Job *)),
01486           mAccount, SLOT(slotSimpleResult(KIO::Job *)));
01487 }
01488 
01489 void KMFolderImap::deleteMessage(const QPtrList<KMMessage>& msgList)
01490 {
01491   QValueList<ulong> uids;
01492   getUids(msgList, uids);
01493   QStringList sets = makeSets(uids);
01494 
01495   KURL url = mAccount->getUrl();
01496   KMFolderImap *msg_parent = static_cast<KMFolderImap*>(msgList.getFirst()->storage());
01497   for ( QStringList::Iterator it = sets.begin(); it != sets.end(); ++it )
01498   {
01499     QString uid = *it;
01500     // Don't delete with no uid, that nukes the folder. Should not happen, but
01501     // better safe than sorry.
01502     if ( uid.isEmpty() ) continue;
01503     url.setPath(msg_parent->imapPath() + ";UID=" + uid);
01504     if ( mAccount->makeConnection() != ImapAccountBase::Connected )
01505       return;
01506     KIO::SimpleJob *job = KIO::file_delete(url, FALSE);
01507     KIO::Scheduler::assignJobToSlave(mAccount->slave(), job);
01508     ImapAccountBase::jobData jd( url.url(), 0 );
01509     mAccount->insertJob(job, jd);
01510     connect(job, SIGNAL(result(KIO::Job *)),
01511         mAccount, SLOT(slotSimpleResult(KIO::Job *)));
01512   }
01513 }
01514 
01515 //-----------------------------------------------------------------------------
01516 void KMFolderImap::setStatus(int idx, KMMsgStatus status, bool toggle)
01517 {
01518   QValueList<int> ids; ids.append(idx);
01519   setStatus(ids, status, toggle);
01520 }
01521 
01522 void KMFolderImap::setStatus(QValueList<int>& ids, KMMsgStatus status, bool toggle)
01523 {
01524   FolderStorage::setStatus(ids, status, toggle);
01525   if (mReadOnly) return;
01526 
01527   /* The status has been already set in the local index. Update the flags on
01528    * the server. To avoid doing that for each message individually, group them
01529    * by the status string they will be assigned and make sets for each of those
01530    * groups of mails. This is necessary because the imap kio_slave status job
01531    * does not append flags but overwrites them. Example:
01532    *
01533    * 2 important mails and 3 unimportant mail, all unread. Mark all as read calls
01534    * this method with a list of uids. The 2 important mails need to get the string
01535    * \SEEN \FLAGGED while the others need to get just \SEEN. Build sets for each
01536    * of those and sort them, so the server can handle them efficiently. */
01537   QMap< QString, QStringList > groups;
01538   for ( QValueList<int>::Iterator it = ids.begin(); it != ids.end(); ++it ) {
01539     KMMessage *msg = 0;
01540     bool unget = !isMessage(*it);
01541     msg = getMsg(*it);
01542     if (!msg) continue;
01543     QString flags = statusToFlags(msg->status());
01544     // Collect uids for each type of flags.
01545     groups[flags].append(QString::number(msg->UID()));
01546     if (unget) unGetMsg(*it);
01547   }
01548   QMapIterator< QString, QStringList > dit;
01549   for ( dit = groups.begin(); dit != groups.end(); ++dit ) {
01550      QCString flags = dit.key().latin1();
01551      QStringList sets = makeSets( (*dit), true );
01552      // Send off a status setting job for each set.
01553      for (  QStringList::Iterator slit = sets.begin(); slit != sets.end(); ++slit ) {
01554        QString imappath = imapPath() + ";UID=" + ( *slit );
01555        mAccount->setImapStatus(folder(), imappath, flags);
01556      }
01557   }
01558   if ( mContentState == imapInProgress ) {
01559     // we're currently get'ing this folder
01560     // to make sure that we get the latest flags abort the current listing and
01561     // create a new one
01562     disconnect(this, SLOT(slotListFolderResult(KIO::Job *)));
01563     reallyGetFolder( QString::null );
01564   }
01565 }
01566 
01567 //-----------------------------------------------------------------------------
01568 QStringList KMFolderImap::makeSets(const QStringList& uids, bool sort)
01569 {
01570   QValueList<ulong> tmp;
01571   for ( QStringList::ConstIterator it = uids.begin(); it != uids.end(); ++it )
01572     tmp.append( (*it).toInt() );
01573   return makeSets(tmp, sort);
01574 }
01575 
01576 QStringList KMFolderImap::makeSets( QValueList<ulong>& uids, bool sort )
01577 {
01578   QStringList sets;
01579   QString set;
01580 
01581   if (uids.size() == 1)
01582   {
01583     sets.append(QString::number(uids.first()));
01584     return sets;
01585   }
01586 
01587   if (sort) qHeapSort(uids);
01588 
01589   ulong last = 0;
01590   // needed to make a uid like 124 instead of 124:124
01591   bool inserted = false;
01592   /* iterate over uids and build sets like 120:122,124,126:150 */
01593   for ( QValueList<ulong>::Iterator it = uids.begin(); it != uids.end(); ++it )
01594   {
01595     if (it == uids.begin() || set.isEmpty()) {
01596       set = QString::number(*it);
01597       inserted = true;
01598     } else
01599     {
01600       if (last+1 != *it)
01601       {
01602         // end this range
01603         if (inserted)
01604           set += ',' + QString::number(*it);
01605         else
01606           set += ':' + QString::number(last) + ',' + QString::number(*it);
01607         inserted = true;
01608         if (set.length() > 100)
01609         {
01610           // just in case the server has a problem with longer lines..
01611           sets.append(set);
01612           set = "";
01613         }
01614       } else {
01615         inserted = false;
01616       }
01617     }
01618     last = *it;
01619   }
01620   // last element
01621   if (!inserted)
01622     set += ':' + QString::number(uids.last());
01623 
01624   if (!set.isEmpty()) sets.append(set);
01625 
01626   return sets;
01627 }
01628 
01629 //-----------------------------------------------------------------------------
01630 void KMFolderImap::getUids(QValueList<int>& ids, QValueList<ulong>& uids)
01631 {
01632   KMMsgBase *msg = 0;
01633   // get the uids
01634   for ( QValueList<int>::Iterator it = ids.begin(); it != ids.end(); ++it )
01635   {
01636     msg = getMsgBase(*it);
01637     if (!msg) continue;
01638     uids.append(msg->UID());
01639   }
01640 }
01641 
01642 void KMFolderImap::getUids(const QPtrList<KMMessage>& msgList, QValueList<ulong>& uids, KMFolder* msgParent)
01643 {
01644   KMMessage *msg = 0;
01645 
01646   if (!msgParent)
01647     msgParent = msgList.getFirst()->parent();
01648   if (!msgParent) return;
01649 
01650   QPtrListIterator<KMMessage> it( msgList );
01651   while ( (msg = it.current()) != 0 ) {
01652     ++it;
01653     uids.append(msg->UID());
01654   }
01655 }
01656 
01657 //-----------------------------------------------------------------------------
01658 void KMFolderImap::expungeFolder(KMFolderImap * aFolder, bool quiet)
01659 {
01660   aFolder->setNeedsCompacting(FALSE);
01661   KURL url = mAccount->getUrl();
01662   url.setPath(aFolder->imapPath() + ";UID=*");
01663   if ( mAccount->makeConnection() != ImapAccountBase::Connected )
01664     return;
01665   KIO::SimpleJob *job = KIO::file_delete(url, FALSE);
01666   KIO::Scheduler::assignJobToSlave(mAccount->slave(), job);
01667   ImapAccountBase::jobData jd( url.url(), 0 );
01668   jd.quiet = quiet;
01669   mAccount->insertJob(job, jd);
01670   connect(job, SIGNAL(result(KIO::Job *)),
01671           mAccount, SLOT(slotSimpleResult(KIO::Job *)));
01672 }
01673 
01674 //-----------------------------------------------------------------------------
01675 void KMFolderImap::slotProcessNewMail( int errorCode, const QString &errorMsg )
01676 {
01677   Q_UNUSED( errorMsg );
01678   disconnect( mAccount, SIGNAL( connectionResult(int, const QString&) ),
01679               this, SLOT( slotProcessNewMail(int, const QString&) ) );
01680   if ( !errorCode )
01681     processNewMail( false );
01682   else
01683     emit numUnreadMsgsChanged( folder() );
01684 }
01685 
01686 //-----------------------------------------------------------------------------
01687 bool KMFolderImap::processNewMail(bool)
01688 {
01689    // a little safety
01690   if ( !mAccount ) {
01691     kdDebug(5006) << "KMFolderImap::processNewMail - account is null!" << endl;
01692     return false;
01693   }
01694   if (imapPath().isEmpty()) {
01695     kdDebug(5006) << "KMFolderImap::processNewMail - imapPath of " << name() << " is empty!" << endl;
01696     kmkernel->imapFolderMgr()->remove( folder() );
01697     return false;
01698   }
01699   // check the connection
01700   if ( mAccount->makeConnection() == ImapAccountBase::Error ) {
01701     kdDebug(5006) << "KMFolderImap::processNewMail - got no connection!" << endl;
01702     return false;
01703   } else if ( mAccount->makeConnection() == ImapAccountBase::Connecting )
01704   {
01705     // wait
01706     kdDebug(5006) << "KMFolderImap::processNewMail - waiting for connection" << endl;
01707     connect( mAccount, SIGNAL( connectionResult(int, const QString&) ),
01708         this, SLOT( slotProcessNewMail(int, const QString&) ) );
01709     return true;
01710   }
01711   KURL url = mAccount->getUrl();
01712   if (mReadOnly)
01713     url.setPath(imapPath() + ";SECTION=UIDNEXT");
01714   else
01715     url.setPath(imapPath() + ";SECTION=UNSEEN");
01716 
01717   mMailCheckProgressItem = ProgressManager::createProgressItem(
01718               "MailCheckAccount" + account()->name(),
01719               "MailCheck" + folder()->prettyURL(),
01720               folder()->prettyURL(),
01721               i18n("updating message counts"),
01722               false,
01723               account()->useSSL() || account()->useTLS() );
01724 
01725   KIO::SimpleJob *job = KIO::stat(url, FALSE);
01726   KIO::Scheduler::assignJobToSlave(mAccount->slave(), job);
01727   ImapAccountBase::jobData jd(url.url(), folder() );
01728   jd.cancellable = true;
01729   mAccount->insertJob(job, jd);
01730   connect(job, SIGNAL(result(KIO::Job *)),
01731           SLOT(slotStatResult(KIO::Job *)));
01732   return true;
01733 }
01734 
01735 
01736 //-----------------------------------------------------------------------------
01737 void KMFolderImap::slotStatResult(KIO::Job * job)
01738 {
01739   ImapAccountBase::JobIterator it = mAccount->findJob(job);
01740   if ( it == mAccount->jobsEnd() ) return;
01741   mAccount->removeJob(it);
01742   slotCompleteMailCheckProgress();
01743   if (job->error())
01744   {
01745     mAccount->handleJobError( job, i18n("Error while getting folder information.") );
01746   } else {
01747     KIO::UDSEntry uds = static_cast<KIO::StatJob*>(job)->statResult();
01748     for (KIO::UDSEntry::ConstIterator it = uds.begin(); it != uds.end(); it++)
01749     {
01750       if ((*it).m_uds == KIO::UDS_SIZE)
01751       {
01752         if (mReadOnly)
01753         {
01754           mGuessedUnreadMsgs = -1;
01755           mGuessedUnreadMsgs = countUnread() + (*it).m_long - lastUid() - 1;
01756           if (mGuessedUnreadMsgs < 0) mGuessedUnreadMsgs = 0;
01757         } else {
01758           mGuessedUnreadMsgs = (*it).m_long;
01759         }
01760       }
01761     }
01762   }
01763   emit numUnreadMsgsChanged( folder() );
01764 }
01765 
01766 //-----------------------------------------------------------------------------
01767 int KMFolderImap::create(bool imap)
01768 {
01769   readConfig();
01770   mUnreadMsgs = -1;
01771   return KMFolderMbox::create(imap);
01772 }
01773 
01774 QValueList<ulong> KMFolderImap::splitSets(const QString uids)
01775 {
01776   QValueList<ulong> uidlist;
01777 
01778   // ex: 1205,1204,1203,1202,1236:1238
01779   QString buffer = QString::null;
01780   int setstart = -1;
01781   // iterate over the uids
01782   for (uint i = 0; i < uids.length(); i++)
01783   {
01784     QChar chr = uids[i];
01785     if (chr == ',')
01786     {
01787       if (setstart > -1)
01788       {
01789         // a range (uid:uid) was before
01790         for (int j = setstart; j <= buffer.toInt(); j++)
01791         {
01792           uidlist.append(j);
01793         }
01794         setstart = -1;
01795       } else {
01796         // single uid
01797         uidlist.append(buffer.toInt());
01798       }
01799       buffer = "";
01800     } else if (chr == ':') {
01801       // remember the start of the range
01802       setstart = buffer.toInt();
01803       buffer = "";
01804     } else if (chr.category() == QChar::Number_DecimalDigit) {
01805       // digit
01806       buffer += chr;
01807     } else {
01808       // ignore
01809     }
01810   }
01811   // process the last data
01812   if (setstart > -1)
01813   {
01814     for (int j = setstart; j <= buffer.toInt(); j++)
01815     {
01816       uidlist.append(j);
01817     }
01818   } else {
01819     uidlist.append(buffer.toInt());
01820   }
01821 
01822   return uidlist;
01823 }
01824 
01825 //-----------------------------------------------------------------------------
01826 int KMFolderImap::expungeContents()
01827 {
01828   int rc = KMFolderMbox::expungeContents();
01829   if (autoExpunge())
01830     expungeFolder(this, true);
01831   getFolder();
01832 
01833   return rc;
01834 }
01835 
01836 //-----------------------------------------------------------------------------
01837 void
01838 KMFolderImap::setUserRights( unsigned int userRights )
01839 {
01840   mUserRights = userRights;
01841   kdDebug(5006) << imapPath() << " setUserRights: " << userRights << endl;
01842 }
01843 
01844 //-----------------------------------------------------------------------------
01845 void KMFolderImap::slotCompleteMailCheckProgress()
01846 {
01847   if ( mMailCheckProgressItem ) {
01848     mMailCheckProgressItem->setComplete();
01849   }
01850 }
01851 
01852 //-----------------------------------------------------------------------------
01853 void KMFolderImap::setSubfolderState( imapState state )
01854 {
01855   mSubfolderState = state;
01856   if ( state == imapNoInformation && folder()->child() )
01857   {
01858     // pass through to childs
01859     KMFolderNode* node;
01860     QPtrListIterator<KMFolderNode> it( *folder()->child() );
01861     for ( ; (node = it.current()); )
01862     {
01863       ++it;
01864       if (node->isDir()) continue;
01865       KMFolder *folder = static_cast<KMFolder*>(node);
01866       static_cast<KMFolderImap*>(folder->storage())->setSubfolderState( state );
01867     }
01868   }
01869 }
01870 
01871 //-----------------------------------------------------------------------------
01872 void KMFolderImap::setIncludeInMailCheck( bool check )
01873 {
01874   bool changed = ( mCheckMail != check );
01875   mCheckMail = check;
01876   if ( changed )
01877     account()->slotUpdateFolderList();
01878 }
01879 
01880 //-----------------------------------------------------------------------------
01881 void KMFolderImap::setAlreadyRemoved( bool removed )
01882 {
01883   mAlreadyRemoved = removed;
01884   if ( folder()->child() )
01885   {
01886     // pass through to childs
01887     KMFolderNode* node;
01888     QPtrListIterator<KMFolderNode> it( *folder()->child() );
01889     for ( ; (node = it.current()); )
01890     {
01891       ++it;
01892       if (node->isDir()) continue;
01893       KMFolder *folder = static_cast<KMFolder*>(node);
01894       static_cast<KMFolderImap*>(folder->storage())->setAlreadyRemoved( removed );
01895     }
01896   }
01897 }
01898 
01899 void KMFolderImap::slotCreatePendingFolders()
01900 {
01901   QStringList::Iterator it = mFoldersPendingCreation.begin();
01902   for ( ; it != mFoldersPendingCreation.end(); ++it ) {
01903     createFolder( *it );
01904   }
01905   mFoldersPendingCreation.clear();
01906 }
01907 
01908 #include "kmfolderimap.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 Fri Dec 21 14:24:53 2007 by doxygen 1.4.2 written by Dimitri van Heesch, © 1997-2003