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