kmail

kmfolderimap.cpp
00001 
00023 #ifdef HAVE_CONFIG_H
00024 #include <config.h>
00025 #endif
00026 
00027 #include "kmfolder.h"
00028 #include "kmfolderimap.h"
00029 #include "kmfoldermbox.h"
00030 #include "kmfoldertree.h"
00031 #include "kmmsgdict.h"
00032 #include "undostack.h"
00033 #include "kmfoldermgr.h"
00034 #include "kmfiltermgr.h"
00035 #include "kmmsgdict.h"
00036 #include "imapaccountbase.h"
00037 using KMail::ImapAccountBase;
00038 #include "imapjob.h"
00039 using KMail::ImapJob;
00040 #include "attachmentstrategy.h"
00041 using KMail::AttachmentStrategy;
00042 #include "progressmanager.h"
00043 using KPIM::ProgressItem;
00044 using KPIM::ProgressManager;
00045 #include "listjob.h"
00046 using KMail::ListJob;
00047 #include "kmsearchpattern.h"
00048 #include "searchjob.h"
00049 using KMail::SearchJob;
00050 #include "renamejob.h"
00051 using KMail::RenameJob;
00052 #include "acljobs.h"
00053 
00054 #include <kdebug.h>
00055 #include <tdeio/scheduler.h>
00056 #include <tdeconfig.h>
00057 
00058 #include <tqbuffer.h>
00059 #include <tqtextcodec.h>
00060 #include <tqstylesheet.h>
00061 
00062 #include <assert.h>
00063 
00064 KMFolderImap::KMFolderImap(KMFolder* folder, const char* aName)
00065   : KMFolderMbox(folder, aName),
00066     mUploadAllFlags( false )
00067 {
00068   mContentState = imapNoInformation;
00069   mSubfolderState = imapNoInformation;
00070   mAccount = 0;
00071   mIsSelected = false;
00072   mLastUid = 0;
00073   mCheckFlags = true;
00074   mCheckMail = true;
00075   mCheckingValidity = false;
00076   mUserRights = 0;
00077   mUserRightsState = KMail::ACLJobs::NotFetchedYet;
00078   mAlreadyRemoved = false;
00079   mHasChildren = ChildrenUnknown;
00080   mMailCheckProgressItem = 0;
00081   mListDirProgressItem = 0;
00082   mAddMessageProgressItem = 0;
00083   mReadOnly = false;
00084 
00085   connect (this, TQT_SIGNAL( folderComplete( KMFolderImap*, bool ) ),
00086            this, TQT_SLOT( slotCompleteMailCheckProgress()) );
00087 }
00088 
00089 KMFolderImap::~KMFolderImap()
00090 {
00091   if (mAccount) {
00092     mAccount->removeSlaveJobsForFolder( folder() );
00093     /* Now that we've removed ourselves from the accounts jobs map, kill all
00094        ongoing operations and reset mailcheck if we were deleted during an
00095        ongoing mailcheck of our account. Not very gracefull, but safe, and the
00096        only way I can see to reset the account state cleanly. */
00097     if ( mAccount->checkingMail( folder() ) ) {
00098        mAccount->killAllJobs();
00099     }
00100   }
00101   writeConfig();
00102   if (kmkernel->undoStack()) kmkernel->undoStack()->folderDestroyed( folder() );
00103   mMetaDataMap.setAutoDelete( true );
00104   mMetaDataMap.clear();
00105   mUidMetaDataMap.setAutoDelete( true );
00106   mUidMetaDataMap.clear();
00107 }
00108 
00109 
00110 //-----------------------------------------------------------------------------
00111 void KMFolderImap::reallyDoClose(const char* owner)
00112 {
00113   // FIXME is this still needed?
00114   if (account())
00115     account()->ignoreJobsForFolder( folder() );
00116   int idx = count();
00117   while (--idx >= 0) {
00118     if ( mMsgList[idx]->isMessage() ) {
00119       KMMessage *msg = static_cast<KMMessage*>(mMsgList[idx]);
00120       if (msg->transferInProgress())
00121           msg->setTransferInProgress( false );
00122     }
00123   }
00124   KMFolderMbox::reallyDoClose( owner );
00125 }
00126 
00127 KMFolder* KMFolderImap::trashFolder() const
00128 {
00129   TQString trashStr = account()->trash();
00130   return kmkernel->imapFolderMgr()->findIdString( trashStr );
00131 }
00132 
00133 //-----------------------------------------------------------------------------
00134 KMMessage* KMFolderImap::getMsg(int idx)
00135 {
00136   if(!(idx >= 0 && idx <= count()))
00137     return 0;
00138 
00139   KMMsgBase* mb = getMsgBase(idx);
00140   if (!mb) return 0;
00141   if (mb->isMessage())
00142   {
00143     return ((KMMessage*)mb);
00144   } else {
00145     KMMessage* msg = FolderStorage::getMsg( idx );
00146     if ( msg ) // set it incomplete as the msg was not transferred from the server
00147       msg->setComplete( false );
00148     return msg;
00149   }
00150 }
00151 
00152 //-----------------------------------------------------------------------------
00153 KMAcctImap* KMFolderImap::account() const
00154 {
00155   if ( !mAccount ) {
00156     KMFolderDir *parentFolderDir = dynamic_cast<KMFolderDir*>( folder()->parent() );
00157     if ( !parentFolderDir ) {
00158       kdWarning() << k_funcinfo << "No parent folder dir found for " << name() << endl;
00159       return 0;
00160     }
00161     KMFolder *parentFolder = parentFolderDir->owner();
00162     if ( !parentFolder ) {
00163       kdWarning() << k_funcinfo << "No parent folder found for " << name() << endl;
00164       return 0;
00165     }
00166     KMFolderImap *parentStorage = dynamic_cast<KMFolderImap*>( parentFolder->storage() );
00167     if ( parentStorage )
00168       mAccount = parentStorage->account();
00169   }
00170   return mAccount;
00171 }
00172 
00173 void KMFolderImap::setAccount(KMAcctImap *aAccount)
00174 {
00175   mAccount = aAccount;
00176   if( !folder() || !folder()->child() ) return;
00177   KMFolderNode* node;
00178   for (node = folder()->child()->first(); node;
00179        node = folder()->child()->next())
00180   {
00181     if (!node->isDir())
00182       static_cast<KMFolderImap*>(static_cast<KMFolder*>(node)->storage())->setAccount(aAccount);
00183   }
00184 }
00185 
00186 //-----------------------------------------------------------------------------
00187 void KMFolderImap::readConfig()
00188 {
00189   TDEConfig* config = KMKernel::config();
00190   TDEConfigGroupSaver saver(config, "Folder-" + folder()->idString());
00191   mCheckMail = config->readBoolEntry("checkmail", true);
00192 
00193   mUidValidity = config->readEntry("UidValidity");
00194   if ( mImapPath.isEmpty() ) {
00195     setImapPath( config->readEntry("ImapPath") );
00196   }
00197   if (TQString(name()).upper() == "INBOX" && mImapPath == "/INBOX/")
00198   {
00199     folder()->setSystemFolder( true );
00200     folder()->setLabel( i18n("inbox") );
00201   }
00202   mNoContent = config->readBoolEntry("NoContent", false);
00203   mReadOnly = config->readBoolEntry("ReadOnly", false);
00204   mUploadAllFlags = config->readBoolEntry( "UploadAllFlags", true );
00205   mPermanentFlags = config->readNumEntry( "PermanentFlags", 31 /* default flags */ );
00206 
00207   KMFolderMbox::readConfig();
00208 }
00209 
00210 //-----------------------------------------------------------------------------
00211 void KMFolderImap::writeConfig()
00212 {
00213   TDEConfig* config = KMKernel::config();
00214   TDEConfigGroupSaver saver(config, "Folder-" + folder()->idString());
00215   config->writeEntry("checkmail", mCheckMail);
00216   config->writeEntry("UidValidity", mUidValidity);
00217   config->writeEntry("ImapPath", mImapPath);
00218   config->writeEntry("NoContent", mNoContent);
00219   config->writeEntry("ReadOnly", mReadOnly);
00220   config->writeEntry( "UploadAllFlags", mUploadAllFlags );
00221   config->writeEntry( "PermanentFlags", mPermanentFlags );
00222   KMFolderMbox::writeConfig();
00223 }
00224 
00225 //-----------------------------------------------------------------------------
00226 void KMFolderImap::remove()
00227 {
00228   if ( mAlreadyRemoved || !account() )
00229   {
00230     // override
00231     FolderStorage::remove();
00232     return;
00233   }
00234   KURL url = account()->getUrl();
00235   url.setPath(imapPath());
00236   if ( account()->makeConnection() == ImapAccountBase::Error ||
00237        imapPath().isEmpty() )
00238   {
00239     emit removed(folder(), false);
00240     return;
00241   }
00242   TDEIO::SimpleJob *job = TDEIO::file_delete(url, false);
00243   TDEIO::Scheduler::assignJobToSlave(account()->slave(), job);
00244   ImapAccountBase::jobData jd(url.url());
00245   jd.progressItem = ProgressManager::createProgressItem(
00246                       "ImapFolderRemove" + ProgressManager::getUniqueID(),
00247                       i18n("Removing folder"),
00248                       i18n( "URL: %1" ).arg( TQStyleSheet::escape( folder()->prettyURL() ) ),
00249                       false,
00250                       account()->useSSL() || account()->useTLS() );
00251   account()->insertJob(job, jd);
00252   connect(job, TQT_SIGNAL(result(TDEIO::Job *)),
00253           this, TQT_SLOT(slotRemoveFolderResult(TDEIO::Job *)));
00254 }
00255 
00256 //-----------------------------------------------------------------------------
00257 void KMFolderImap::slotRemoveFolderResult(TDEIO::Job *job)
00258 {
00259   ImapAccountBase::JobIterator it = account()->findJob(job);
00260   if ( it == account()->jobsEnd() ) return;
00261   if (job->error())
00262   {
00263     account()->handleJobError( job, i18n("Error while removing a folder.") );
00264     emit removed(folder(), false);
00265   } else {
00266     account()->removeJob(it);
00267     FolderStorage::remove();
00268   }
00269 
00270 }
00271 
00272 //-----------------------------------------------------------------------------
00273 void KMFolderImap::removeMsg(int idx, bool quiet)
00274 {
00275   if (idx < 0)
00276     return;
00277 
00278   if (!quiet)
00279   {
00280     KMMessage *msg = getMsg(idx);
00281     deleteMessage(msg);
00282   }
00283 
00284   mLastUid = 0;
00285   KMFolderMbox::removeMsg(idx);
00286 }
00287 
00288 void KMFolderImap::removeMsg( const TQPtrList<KMMessage>& msgList, bool quiet )
00289 {
00290   if ( msgList.isEmpty() ) return;
00291   if (!quiet)
00292     deleteMessage(msgList);
00293 
00294   mLastUid = 0;
00295 
00296   /* Remove the messages from the local store as well.
00297      We don't call KMFolderInherited::removeMsg(TQPtrList<KMMessage>) but
00298      iterate ourselves, as that would call KMFolderImap::removeMsg(int)
00299      and not the one from the store we want to be used. */
00300 
00301   TQPtrListIterator<KMMessage> it( msgList );
00302   KMMessage *msg;
00303   while ( (msg = it.current()) != 0 ) {
00304     ++it;
00305     int idx = find(msg);
00306     assert( idx != -1);
00307     // ATTENTION port me to maildir
00308     KMFolderMbox::removeMsg(idx, quiet);
00309   }
00310 }
00311 
00312 //-----------------------------------------------------------------------------
00313 int KMFolderImap::rename( const TQString& newName, KMFolderDir *aParent )
00314 {
00315   if ( !aParent )
00316     KMFolderMbox::rename( newName );
00317   kmkernel->folderMgr()->contentsChanged();
00318   return 0;
00319 }
00320 
00321 //-----------------------------------------------------------------------------
00322 void KMFolderImap::addMsgQuiet(KMMessage* aMsg)
00323 {
00324   KMFolder *aFolder = aMsg->parent();
00325   TQ_UINT32 serNum = 0;
00326   aMsg->setTransferInProgress( false );
00327   if (aFolder) {
00328     serNum = aMsg->getMsgSerNum();
00329     kmkernel->undoStack()->pushSingleAction( serNum, aFolder, folder() );
00330     int idx = aFolder->find( aMsg );
00331     assert( idx != -1 );
00332     aFolder->take( idx );
00333   }
00334   if ( !account()->hasCapability("uidplus") ) {
00335     // Remember the status with the MD5 as key
00336     // so it can be transfered to the new message
00337     mMetaDataMap.insert( aMsg->msgIdMD5(),
00338         new KMMsgMetaData(aMsg->status(), serNum) );
00339   }
00340 
00341   delete aMsg;
00342   aMsg = 0;
00343   getFolder();
00344 }
00345 
00346 //-----------------------------------------------------------------------------
00347 void KMFolderImap::addMsgQuiet(TQPtrList<KMMessage> msgList)
00348 {
00349   if ( mAddMessageProgressItem )
00350   {
00351     mAddMessageProgressItem->setComplete();
00352     mAddMessageProgressItem = 0;
00353   }
00354   KMFolder *aFolder = msgList.first()->parent();
00355   int undoId = -1;
00356   bool uidplus = account()->hasCapability("uidplus");
00357   for ( KMMessage* msg = msgList.first(); msg; msg = msgList.next() )
00358   {
00359     if ( undoId == -1 )
00360       undoId = kmkernel->undoStack()->newUndoAction( aFolder, folder() );
00361     if ( msg->getMsgSerNum() > 0 )
00362       kmkernel->undoStack()->addMsgToAction( undoId, msg->getMsgSerNum() );
00363     if ( !uidplus ) {
00364       // Remember the status with the MD5 as key
00365       // so it can be transfered to the new message
00366       mMetaDataMap.insert( msg->msgIdMD5(),
00367           new KMMsgMetaData(msg->status(), msg->getMsgSerNum()) );
00368     }
00369     msg->setTransferInProgress( false );
00370   }
00371   if ( aFolder ) {
00372     aFolder->take( msgList );
00373   } else {
00374     kdDebug(5006) << k_funcinfo << "no parent" << endl;
00375   }
00376   msgList.setAutoDelete(true);
00377   msgList.clear();
00378   getFolder();
00379 }
00380 
00381 //-----------------------------------------------------------------------------
00382 int KMFolderImap::addMsg(KMMessage* aMsg, int* aIndex_ret)
00383 {
00384   TQPtrList<KMMessage> list;
00385   list.append(aMsg);
00386   TQValueList<int> index;
00387   int ret = addMsg(list, index);
00388   aIndex_ret = &index.first();
00389   return ret;
00390 }
00391 
00392 int KMFolderImap::addMsg(TQPtrList<KMMessage>& msgList, TQValueList<int>& aIndex_ret)
00393 {
00394   KMMessage *aMsg = msgList.getFirst();
00395   KMFolder *msgParent = aMsg->parent();
00396 
00397   ImapJob *imapJob = 0;
00398   if (msgParent)
00399   {
00400     if (msgParent->folderType() == KMFolderTypeImap)
00401     {
00402       if (static_cast<KMFolderImap*>(msgParent->storage())->account() == account())
00403       {
00404         // make sure the messages won't be deleted while we work with them
00405         for ( KMMessage* msg = msgList.first(); msg; msg = msgList.next() )
00406           msg->setTransferInProgress(true);
00407 
00408         if (folder() == msgParent)
00409         {
00410           // transfer the whole message, e.g. a draft-message is canceled and re-added to the drafts-folder
00411           for ( KMMessage* msg = msgList.first(); msg; msg = msgList.next() )
00412           {
00413             if (!msg->isComplete())
00414             {
00415               int idx = msgParent->find(msg);
00416               assert(idx != -1);
00417               msg = msgParent->getMsg(idx);
00418             }
00419             imapJob = new ImapJob(msg, ImapJob::tPutMessage, this);
00420             connect(imapJob, TQT_SIGNAL(messageStored(KMMessage*)),
00421                      TQT_SLOT(addMsgQuiet(KMMessage*)));
00422             connect(imapJob, TQT_SIGNAL(result(KMail::FolderJob*)),
00423                 TQT_SLOT(slotCopyMsgResult(KMail::FolderJob*)));
00424             imapJob->start();
00425           }
00426 
00427         } else {
00428 
00429           // get the messages and the uids
00430           TQValueList<ulong> uids;
00431           getUids(msgList, uids);
00432 
00433           // get the sets (do not sort the uids)
00434           TQStringList sets = makeSets(uids, false);
00435 
00436           for ( TQStringList::Iterator it = sets.begin(); it != sets.end(); ++it )
00437           {
00438             // we need the messages that belong to the current set to pass them to the ImapJob
00439             TQPtrList<KMMessage> temp_msgs = splitMessageList(*it, msgList);
00440             if ( temp_msgs.isEmpty() ) kdDebug(5006) << "Wow! KMFolderImap::splitMessageList() returned an empty list!" << endl;
00441             imapJob = new ImapJob(temp_msgs, *it, ImapJob::tMoveMessage, this);
00442             connect(imapJob, TQT_SIGNAL(messageCopied(TQPtrList<KMMessage>)),
00443                 TQT_SLOT(addMsgQuiet(TQPtrList<KMMessage>)));
00444             connect(imapJob, TQT_SIGNAL(result(KMail::FolderJob*)),
00445                 TQT_SLOT(slotCopyMsgResult(KMail::FolderJob*)));
00446             imapJob->start();
00447           }
00448         }
00449         return 0;
00450       }
00451       else
00452       {
00453         // different account, check if messages can be added
00454         TQPtrListIterator<KMMessage> it( msgList );
00455         KMMessage *msg;
00456         while ( (msg = it.current()) != 0 )
00457         {
00458           ++it;
00459           int index;
00460           if (!canAddMsgNow(msg, &index)) {
00461             aIndex_ret << index;
00462             msgList.remove(msg);
00463           } else {
00464             if (!msg->transferInProgress())
00465               msg->setTransferInProgress(true);
00466           }
00467         }
00468       }
00469     } // if imap
00470   }
00471 
00472   if ( !msgList.isEmpty() )
00473   {
00474     // transfer from local folders or other accounts
00475     TQPtrListIterator<KMMessage> it( msgList );
00476     KMMessage* msg;
00477     while ( ( msg = it.current() ) != 0 )
00478     {
00479       ++it;
00480       if ( !msg->transferInProgress() )
00481         msg->setTransferInProgress( true );
00482     }
00483     imapJob = new ImapJob( msgList, TQString(), ImapJob::tPutMessage, this );
00484     if ( !mAddMessageProgressItem && msgList.count() > 1 )
00485     {
00486       // use a parent progress if we have more than 1 message
00487       // otherwise the normal progress is more accurate
00488       mAddMessageProgressItem = ProgressManager::createProgressItem(
00489           "Uploading"+ProgressManager::getUniqueID(),
00490           i18n("Uploading message data"),
00491           i18n("Destination folder: %1").arg( TQStyleSheet::escape( folder()->prettyURL() ) ),
00492           true,
00493           account()->useSSL() || account()->useTLS() );
00494       mAddMessageProgressItem->setTotalItems( msgList.count() );
00495       connect ( mAddMessageProgressItem, TQT_SIGNAL( progressItemCanceled( KPIM::ProgressItem*)),
00496           account(), TQT_SLOT( slotAbortRequested( KPIM::ProgressItem* ) ) );
00497       imapJob->setParentProgressItem( mAddMessageProgressItem );
00498     }
00499     connect( imapJob, TQT_SIGNAL( messageCopied(TQPtrList<KMMessage>) ),
00500         TQT_SLOT( addMsgQuiet(TQPtrList<KMMessage>) ) );
00501     connect( imapJob, TQT_SIGNAL(result(KMail::FolderJob*)),
00502              TQT_SLOT(slotCopyMsgResult(KMail::FolderJob*)) );
00503     imapJob->start();
00504   }
00505 
00506   return 0;
00507 }
00508 
00509 //-----------------------------------------------------------------------------
00510 void KMFolderImap::slotCopyMsgResult( KMail::FolderJob* job )
00511 {
00512   kdDebug(5006) << k_funcinfo << job->error() << endl;
00513   if ( job->error() ) // getFolder() will not be called in this case
00514     emit folderComplete( this, false );
00515 }
00516 
00517 //-----------------------------------------------------------------------------
00518 void KMFolderImap::copyMsg(TQPtrList<KMMessage>& msgList)
00519 {
00520   if ( !account()->hasCapability("uidplus") ) {
00521     for ( KMMessage *msg = msgList.first(); msg; msg = msgList.next() ) {
00522       // Remember the status with the MD5 as key
00523       // so it can be transfered to the new message
00524       mMetaDataMap.insert( msg->msgIdMD5(), new KMMsgMetaData(msg->status()) );
00525     }
00526   }
00527 
00528   TQValueList<ulong> uids;
00529   getUids(msgList, uids);
00530   TQStringList sets = makeSets(uids, false);
00531   for ( TQStringList::Iterator it = sets.begin(); it != sets.end(); ++it )
00532   {
00533     // we need the messages that belong to the current set to pass them to the ImapJob
00534     TQPtrList<KMMessage> temp_msgs = splitMessageList(*it, msgList);
00535 
00536     ImapJob *job = new ImapJob(temp_msgs, *it, ImapJob::tCopyMessage, this);
00537     connect(job, TQT_SIGNAL(result(KMail::FolderJob*)),
00538             TQT_SLOT(slotCopyMsgResult(KMail::FolderJob*)));
00539     job->start();
00540   }
00541 }
00542 
00543 //-----------------------------------------------------------------------------
00544 TQPtrList<KMMessage> KMFolderImap::splitMessageList(const TQString& set,
00545                                                    TQPtrList<KMMessage>& msgList)
00546 {
00547   int lastcomma = set.findRev(",");
00548   int lastdub = set.findRev(":");
00549   int last = 0;
00550   if (lastdub > lastcomma) last = lastdub;
00551   else last = lastcomma;
00552   last++;
00553   if (last < 0) last = set.length();
00554   // the last uid of the current set
00555   const TQString last_uid = set.right(set.length() - last);
00556   TQPtrList<KMMessage> temp_msgs;
00557   TQString uid;
00558   if (!last_uid.isEmpty())
00559   {
00560     TQPtrListIterator<KMMessage> it( msgList );
00561     KMMessage* msg = 0;
00562     while ( (msg = it.current()) != 0 )
00563     {
00564       // append the msg to the new list and delete it from the old
00565       temp_msgs.append(msg);
00566       uid.setNum( msg->UID() );
00567       // remove modifies the current
00568       msgList.remove(msg);
00569       if (uid == last_uid) break;
00570     }
00571   }
00572   else
00573   {
00574     // probably only one element
00575     temp_msgs = msgList;
00576   }
00577 
00578   return temp_msgs;
00579 }
00580 
00581 //-----------------------------------------------------------------------------
00582 KMMessage* KMFolderImap::take(int idx)
00583 {
00584   KMMsgBase* mb(mMsgList[idx]);
00585   if (!mb) return 0;
00586   if (!mb->isMessage()) readMsg(idx);
00587 
00588   KMMessage *msg = static_cast<KMMessage*>(mb);
00589   deleteMessage(msg);
00590 
00591   mLastUid = 0;
00592   return KMFolderMbox::take(idx);
00593 }
00594 
00595 void KMFolderImap::take(TQPtrList<KMMessage> msgList)
00596 {
00597   deleteMessage(msgList);
00598 
00599   mLastUid = 0;
00600   KMFolderMbox::take(msgList);
00601 }
00602 
00603 //-----------------------------------------------------------------------------
00604 void KMFolderImap::slotListNamespaces()
00605 {
00606   disconnect( account(), TQT_SIGNAL( connectionResult(int, const TQString&) ),
00607       this, TQT_SLOT( slotListNamespaces() ) );
00608   if ( account()->makeConnection() == ImapAccountBase::Error )
00609   {
00610     kdWarning(5006) << "slotListNamespaces - got no connection" << endl;
00611     return;
00612   } else if ( account()->makeConnection() == ImapAccountBase::Connecting )
00613   {
00614     // wait for the connectionResult
00615     kdDebug(5006) << "slotListNamespaces - waiting for connection" << endl;
00616     connect( account(), TQT_SIGNAL( connectionResult(int, const TQString&) ),
00617         this, TQT_SLOT( slotListNamespaces() ) );
00618     return;
00619   }
00620   kdDebug(5006) << "slotListNamespaces" << endl;
00621   // reset subfolder states recursively
00622   setSubfolderState( imapNoInformation );
00623   mSubfolderState = imapListingInProgress;
00624   account()->setHasInbox( false );
00625 
00626   ImapAccountBase::ListType type = ImapAccountBase::List;
00627   if ( account()->onlySubscribedFolders() )
00628     type = ImapAccountBase::ListSubscribed;
00629 
00630   ImapAccountBase::nsMap map = account()->namespaces();
00631   TQStringList personal = map[ImapAccountBase::PersonalNS];
00632   // start personal namespace listing and send it directly to slotListResult
00633   for ( TQStringList::Iterator it = personal.begin(); it != personal.end(); ++it )
00634   {
00635     KMail::ListJob* job = new KMail::ListJob( account(), type, this,
00636     account()->addPathToNamespace( *it ) );
00637     job->setNamespace( *it );
00638     job->setHonorLocalSubscription( true );
00639     connect( job, TQT_SIGNAL(receivedFolders(const TQStringList&, const TQStringList&,
00640             const TQStringList&, const TQStringList&, const ImapAccountBase::jobData&)),
00641         this, TQT_SLOT(slotListResult(const TQStringList&, const TQStringList&,
00642             const TQStringList&, const TQStringList&, const ImapAccountBase::jobData&)));
00643     job->start();
00644   }
00645 
00646   // and now we list all other namespaces and check them ourself
00647   TQStringList ns = map[ImapAccountBase::OtherUsersNS];
00648   ns += map[ImapAccountBase::SharedNS];
00649   for ( TQStringList::Iterator it = ns.begin(); it != ns.end(); ++it )
00650   {
00651     KMail::ListJob* job = new  KMail::ListJob( account(), type, this, account()->addPathToNamespace( *it ) );
00652     job->setHonorLocalSubscription( true );
00653     connect( job, TQT_SIGNAL(receivedFolders(const TQStringList&, const TQStringList&,
00654             const TQStringList&, const TQStringList&, const ImapAccountBase::jobData&)),
00655         this, TQT_SLOT(slotCheckNamespace(const TQStringList&, const TQStringList&,
00656             const TQStringList&, const TQStringList&, const ImapAccountBase::jobData&)));
00657     job->start();
00658   }
00659 }
00660 
00661 //-----------------------------------------------------------------------------
00662 void KMFolderImap::slotCheckNamespace( const TQStringList& subfolderNames,
00663                                        const TQStringList& subfolderPaths,
00664                                        const TQStringList& subfolderMimeTypes,
00665                                        const TQStringList& subfolderAttributes,
00666                                        const ImapAccountBase::jobData& jobData )
00667 {
00668   kdDebug(5006) << "slotCheckNamespace - " << subfolderNames.join(",") << endl;
00669 
00670   // get a correct foldername:
00671   // strip / and make sure it does not contain the delimiter
00672   TQString name = jobData.path.mid( 1, jobData.path.length()-2 );
00673   name.remove( account()->delimiterForNamespace( name ) );
00674   if ( name.isEmpty() ) {
00675     // happens when an empty namespace is defined
00676     slotListResult( subfolderNames, subfolderPaths,
00677         subfolderMimeTypes, subfolderAttributes, jobData );
00678     return;
00679   }
00680 
00681   folder()->createChildFolder();
00682   KMFolderNode *node = 0;
00683   for ( node = folder()->child()->first(); node;
00684         node = folder()->child()->next())
00685   {
00686     if ( !node->isDir() && node->name() == name )
00687       break;
00688   }
00689   if ( subfolderNames.isEmpty() )
00690   {
00691     if ( node )
00692     {
00693       kdDebug(5006) << "delete namespace folder " << name << endl;
00694       KMFolder *fld = static_cast<KMFolder*>(node);
00695       KMFolderImap* nsFolder = static_cast<KMFolderImap*>(fld->storage());
00696       nsFolder->setAlreadyRemoved( true );
00697       kmkernel->imapFolderMgr()->remove( fld );
00698     }
00699   } else {
00700     if ( node )
00701     {
00702       // folder exists so pass on the attributes
00703       kdDebug(5006) << "found namespace folder " << name << endl;
00704       if ( !account()->listOnlyOpenFolders() )
00705       {
00706         KMFolderImap* nsFolder =
00707           static_cast<KMFolderImap*>(static_cast<KMFolder*>(node)->storage());
00708         nsFolder->slotListResult( subfolderNames, subfolderPaths,
00709             subfolderMimeTypes, subfolderAttributes, jobData );
00710       }
00711     } else
00712     {
00713       // create folder
00714       kdDebug(5006) << "create namespace folder " << name << endl;
00715       KMFolder *fld = folder()->child()->createFolder( name );
00716       if ( fld ) {
00717         KMFolderImap* f = static_cast<KMFolderImap*> ( fld->storage() );
00718         f->initializeFrom( this, account()->addPathToNamespace( name ),
00719             "inode/directory" );
00720         f->close( "kmfolderimap_create" );
00721         if ( !account()->listOnlyOpenFolders() )
00722         {
00723           f->slotListResult( subfolderNames, subfolderPaths,
00724               subfolderMimeTypes, subfolderAttributes, jobData );
00725         }
00726       }
00727       kmkernel->imapFolderMgr()->contentsChanged();
00728     }
00729   }
00730 }
00731 
00732 //-----------------------------------------------------------------------------
00733 bool KMFolderImap::listDirectory()
00734 {
00735   if ( !account() ||
00736        ( account() && account()->makeConnection() == ImapAccountBase::Error ) )
00737   {
00738     kdDebug(5006) << "KMFolderImap::listDirectory - got no connection" << endl;
00739     return false;
00740   }
00741 
00742   if ( this == account()->rootFolder() )
00743   {
00744     // a new listing started
00745     slotListNamespaces();
00746     return true;
00747   }
00748   mSubfolderState = imapListingInProgress;
00749 
00750   // get the folders
00751   ImapAccountBase::ListType type = ImapAccountBase::List;
00752   if ( account()->onlySubscribedFolders() )
00753     type = ImapAccountBase::ListSubscribed;
00754   KMail::ListJob* job = new  KMail::ListJob( account(), type, this );
00755   job->setParentProgressItem( account()->listDirProgressItem() );
00756   job->setHonorLocalSubscription( true );
00757   connect( job, TQT_SIGNAL(receivedFolders(const TQStringList&, const TQStringList&,
00758           const TQStringList&, const TQStringList&, const ImapAccountBase::jobData&)),
00759       this, TQT_SLOT(slotListResult(const TQStringList&, const TQStringList&,
00760           const TQStringList&, const TQStringList&, const ImapAccountBase::jobData&)));
00761   job->start();
00762 
00763   return true;
00764 }
00765 
00766 
00767 //-----------------------------------------------------------------------------
00768 void KMFolderImap::slotListResult( const TQStringList& subfolderNames,
00769                                    const TQStringList& subfolderPaths,
00770                                    const TQStringList& subfolderMimeTypes,
00771                                    const TQStringList& subfolderAttributes,
00772                                    const ImapAccountBase::jobData& jobData )
00773 {
00774   mSubfolderState = imapFinished;
00775   //kdDebug(5006) << label() << ": folderNames=" << subfolderNames << " folderPaths="
00776   //<< subfolderPaths << " mimeTypes=" << subfolderMimeTypes << endl;
00777 
00778   // don't react on changes
00779   kmkernel->imapFolderMgr()->quiet(true);
00780 
00781   bool root = ( this == account()->rootFolder() );
00782   folder()->createChildFolder();
00783   if ( root && !account()->hasInbox() )
00784   {
00785     // create the INBOX
00786     initInbox();
00787   }
00788 
00789   // see if we have a better parent
00790   // if you have a prefix that contains a folder (e.g "INBOX.") the folders
00791   // need to be created underneath it
00792   if ( root && !subfolderNames.empty() )
00793   {
00794     KMFolderImap* parent = findParent( subfolderPaths.first(), subfolderNames.first() );
00795     if ( parent )
00796     {
00797       kdDebug(5006) << "KMFolderImap::slotListResult - pass listing to "
00798         << parent->label() << endl;
00799       parent->slotListResult( subfolderNames, subfolderPaths,
00800           subfolderMimeTypes, subfolderAttributes, jobData );
00801       // cleanup
00802       TQStringList list;
00803       checkFolders( list, jobData.curNamespace );
00804       // finish
00805       emit directoryListingFinished( this );
00806       kmkernel->imapFolderMgr()->quiet( false );
00807       return;
00808     }
00809   }
00810 
00811   bool emptyList = ( root && subfolderNames.empty() );
00812   if ( !emptyList )
00813   {
00814     checkFolders( subfolderNames, jobData.curNamespace );
00815   }
00816 
00817   KMFolderImap *f = 0;
00818   KMFolderNode *node = 0;
00819   for ( uint i = 0; i < subfolderNames.count(); i++ )
00820   {
00821     bool settingsChanged = false;
00822     // create folders if necessary
00823     for ( node = folder()->child()->first(); node;
00824           node = folder()->child()->next() ) {
00825       if ( !node->isDir() && node->name() == subfolderNames[i] )
00826         break;
00827     }
00828     if ( node ) {
00829       f = static_cast<KMFolderImap*>(static_cast<KMFolder*>(node)->storage());
00830     }
00831     else if ( subfolderPaths[i].upper() != "/INBOX/" )
00832     {
00833       kdDebug(5006) << "create folder " << subfolderNames[i] << endl;
00834       KMFolder *fld = folder()->child()->createFolder(subfolderNames[i]);
00835       if ( fld ) {
00836         f = static_cast<KMFolderImap*> ( fld->storage() );
00837         f->close( "kmfolderimap_create" );
00838         settingsChanged = true;
00839       } else {
00840         kdWarning(5006) << "can't create folder " << subfolderNames[i] << endl;
00841       }
00842     }
00843     if ( f )
00844     {
00845       // sanity check
00846       if ( f->imapPath().isEmpty() ) {
00847         settingsChanged = true;
00848       }
00849       // update progress
00850       account()->listDirProgressItem()->incCompletedItems();
00851       account()->listDirProgressItem()->updateProgress();
00852       account()->listDirProgressItem()->setStatus( folder()->prettyURL() + i18n(" completed") );
00853 
00854       f->initializeFrom( this, subfolderPaths[i], subfolderMimeTypes[i] );
00855       f->setChildrenState( subfolderAttributes[i] );
00856       if ( account()->listOnlyOpenFolders() &&
00857            f->hasChildren() != FolderStorage::ChildrenUnknown )
00858       {
00859         settingsChanged = true;
00860       }
00861 
00862       if ( settingsChanged )
00863       {
00864         // tell the tree our information changed
00865         kmkernel->imapFolderMgr()->contentsChanged();
00866       }
00867       if ( ( subfolderMimeTypes[i] == "message/directory" ||
00868              subfolderMimeTypes[i] == "inode/directory" ) &&
00869            !account()->listOnlyOpenFolders() )
00870       {
00871         f->listDirectory();
00872       }
00873     } else {
00874       kdWarning(5006) << "can't find folder " << subfolderNames[i] << endl;
00875     }
00876   } // for subfolders
00877 
00878   // now others should react on the changes
00879   kmkernel->imapFolderMgr()->quiet( false );
00880   emit directoryListingFinished( this );
00881   account()->listDirProgressItem()->setComplete();
00882 }
00883 
00884 //-----------------------------------------------------------------------------
00885 void KMFolderImap::initInbox()
00886 {
00887   KMFolderImap *f = 0;
00888   KMFolderNode *node = 0;
00889 
00890   for (node = folder()->child()->first(); node;
00891       node = folder()->child()->next()) {
00892     if (!node->isDir() && node->name() == "INBOX") break;
00893   }
00894   if (node) {
00895     f = static_cast<KMFolderImap*>(static_cast<KMFolder*>(node)->storage());
00896   } else {
00897     f = static_cast<KMFolderImap*>
00898       (folder()->child()->createFolder("INBOX", true)->storage());
00899     if ( f )
00900     {
00901       f->folder()->setLabel( i18n("inbox") );
00902       f->close( "kmfolderimap" );
00903     }
00904     kmkernel->imapFolderMgr()->contentsChanged();
00905   }
00906   if ( f ) {
00907     f->initializeFrom( this, "/INBOX/", "message/directory" );
00908     f->setChildrenState( TQString() );
00909   }
00910   // so we have an INBOX
00911   account()->setHasInbox( true );
00912 }
00913 
00914 //-----------------------------------------------------------------------------
00915 KMFolderImap* KMFolderImap::findParent( const TQString& path, const TQString& name )
00916 {
00917   TQString parent = path.left( path.length() - name.length() - 2 );
00918   if ( parent.length() > 1 )
00919   {
00920     // extract name of the parent
00921     parent = parent.right( parent.length() - 1 );
00922     if ( parent != label() )
00923     {
00924       KMFolderNode *node = folder()->child()->first();
00925       // look for a better parent
00926       while ( node )
00927       {
00928         if ( node->name() == parent )
00929         {
00930           KMFolder* fld = static_cast<KMFolder*>(node);
00931           KMFolderImap* imapFld = static_cast<KMFolderImap*>( fld->storage() );
00932           return imapFld;
00933         }
00934         node = folder()->child()->next();
00935       }
00936     }
00937   }
00938   return 0;
00939 }
00940 
00941 //-----------------------------------------------------------------------------
00942 void KMFolderImap::checkFolders( const TQStringList& subfolderNames,
00943     const TQString& myNamespace )
00944 {
00945   TQPtrList<KMFolder> toRemove;
00946   KMFolderNode *node = folder()->child()->first();
00947   while ( node )
00948   {
00949     if ( !node->isDir() && subfolderNames.findIndex(node->name()) == -1 )
00950     {
00951       KMFolder* fld = static_cast<KMFolder*>(node);
00952       KMFolderImap* imapFld = static_cast<KMFolderImap*>( fld->storage() );
00953       // as more than one namespace can be listed in the root folder we need to make sure
00954       // that the folder is within the current namespace
00955       bool isInNamespace = ( myNamespace.isEmpty() ||
00956           myNamespace == account()->namespaceForFolder( imapFld ) );
00957       kdDebug(5006) << node->name() << " in namespace " << myNamespace << ":" <<
00958         isInNamespace << endl;
00959       // ignore some cases
00960       TQString name = node->name();
00961       bool ignore = ( ( this == account()->rootFolder() ) &&
00962           ( imapFld->imapPath() == "/INBOX/" ||
00963             account()->isNamespaceFolder( name ) ||
00964         !isInNamespace ) );
00965       // additional sanity check for broken folders
00966       if ( imapFld->imapPath().isEmpty() ) {
00967         ignore = false;
00968       }
00969       if ( !ignore )
00970       {
00971         // remove the folder without server round trip
00972         kdDebug(5006) << "checkFolders - " << node->name() << " disappeared" << endl;
00973         imapFld->setAlreadyRemoved( true );
00974         toRemove.append( fld );
00975       } else {
00976         kdDebug(5006) << "checkFolders - " << node->name() << " ignored" << endl;
00977       }
00978     }
00979     node = folder()->child()->next();
00980   }
00981   // remove folders
00982   for ( KMFolder* doomed=toRemove.first(); doomed; doomed = toRemove.next() )
00983     kmkernel->imapFolderMgr()->remove( doomed );
00984 }
00985 
00986 //-----------------------------------------------------------------------------
00987 void KMFolderImap::initializeFrom( KMFolderImap* parent, TQString folderPath,
00988                                    TQString mimeType )
00989 {
00990   setAccount( parent->account() );
00991   setImapPath( folderPath );
00992   setNoContent( mimeType == "inode/directory" );
00993   setNoChildren( mimeType == "message/digest" );
00994 }
00995 
00996 //-----------------------------------------------------------------------------
00997 bool KMFolderImap::mailCheckInProgress() const
00998 {
00999   return getContentState() != imapNoInformation &&
01000          getContentState() != imapFinished;
01001 }
01002 
01003 //-----------------------------------------------------------------------------
01004 void KMFolderImap::setChildrenState( TQString attributes )
01005 {
01006   // update children state
01007   if ( attributes.find( "haschildren", 0, false ) != -1 )
01008   {
01009     setHasChildren( FolderStorage::HasChildren );
01010   } else if ( attributes.find( "hasnochildren", 0, false ) != -1 ||
01011               attributes.find( "noinferiors", 0, false ) != -1 )
01012   {
01013     setHasChildren( FolderStorage::HasNoChildren );
01014   } else
01015   {
01016     if ( account()->listOnlyOpenFolders() ) {
01017       setHasChildren( FolderStorage::HasChildren );
01018     } else {
01019       setHasChildren( FolderStorage::ChildrenUnknown );
01020     }
01021   }
01022 }
01023 
01024 //-----------------------------------------------------------------------------
01025 void KMFolderImap::checkValidity()
01026 {
01027   if (!account()) {
01028     emit folderComplete(this, false);
01029     close("checkvalidity");
01030     return;
01031   }
01032   KURL url = account()->getUrl();
01033   url.setPath(imapPath() + ";UID=0:0");
01034   kdDebug(5006) << "KMFolderImap::checkValidity of: " << imapPath() << endl;
01035 
01036   // Start with a clean slate
01037   disconnect( account(), TQT_SIGNAL( connectionResult(int, const TQString&) ),
01038               this, TQT_SLOT( checkValidity() ) );
01039 
01040   KMAcctImap::ConnectionState connectionState = account()->makeConnection();
01041   if ( connectionState == ImapAccountBase::Error ) {
01042     kdDebug(5006) << "KMFolderImap::checkValidity - got no connection" << endl;
01043     emit folderComplete(this, false);
01044     mContentState = imapNoInformation;
01045     close("checkvalidity");
01046     return;
01047   } else if ( connectionState == ImapAccountBase::Connecting ) {
01048     // We'll wait for the connectionResult signal from the account. If it
01049     // errors, the above will catch it.
01050     kdDebug(5006) << "CheckValidity - waiting for connection" << endl;
01051     connect( account(), TQT_SIGNAL( connectionResult(int, const TQString&) ),
01052         this, TQT_SLOT( checkValidity() ) );
01053     return;
01054   }
01055   // Only check once at a time.
01056   if (mCheckingValidity) {
01057     kdDebug(5006) << "KMFolderImap::checkValidity - already checking" << endl;
01058     close("checkvalidity");
01059     return;
01060   }
01061   // otherwise we already are inside a mailcheck
01062   if ( !mMailCheckProgressItem ) {
01063     ProgressItem* parent = ( account()->checkingSingleFolder() ? 0 :
01064         account()->mailCheckProgressItem() );
01065     mMailCheckProgressItem = ProgressManager::createProgressItem(
01066               parent,
01067               "MailCheck" + folder()->prettyURL(),
01068               TQStyleSheet::escape( folder()->prettyURL() ),
01069               i18n("checking"),
01070               false,
01071               account()->useSSL() || account()->useTLS() );
01072   } else {
01073     mMailCheckProgressItem->setProgress(0);
01074   }
01075   if ( account()->mailCheckProgressItem() ) {
01076     account()->mailCheckProgressItem()->setStatus( folder()->prettyURL() );
01077   }
01078   ImapAccountBase::jobData jd( url.url() );
01079   TDEIO::SimpleJob *job = TDEIO::get(url, false, false);
01080   TDEIO::Scheduler::assignJobToSlave(account()->slave(), job);
01081   account()->insertJob(job, jd);
01082   connect(job, TQT_SIGNAL(result(TDEIO::Job *)),
01083           TQT_SLOT(slotCheckValidityResult(TDEIO::Job *)));
01084   connect(job, TQT_SIGNAL(data(TDEIO::Job *, const TQByteArray &)),
01085           TQT_SLOT(slotSimpleData(TDEIO::Job *, const TQByteArray &)));
01086   // Only check once at a time.
01087   mCheckingValidity = true;
01088 }
01089 
01090 
01091 //-----------------------------------------------------------------------------
01092 ulong KMFolderImap::lastUid()
01093 {
01094   if ( mLastUid > 0 )
01095       return mLastUid;
01096   open("lastuid");
01097   if (count() > 0)
01098   {
01099     KMMsgBase * base = getMsgBase(count()-1);
01100     mLastUid = base->UID();
01101   }
01102   close("lastuid");
01103   return mLastUid;
01104 }
01105 
01106 
01107 //-----------------------------------------------------------------------------
01108 void KMFolderImap::slotCheckValidityResult(TDEIO::Job * job)
01109 {
01110   kdDebug(5006) << "KMFolderImap::slotCheckValidityResult of: " << fileName() << endl;
01111   mCheckingValidity = false;
01112   ImapAccountBase::JobIterator it = account()->findJob(job);
01113   if ( it == account()->jobsEnd() ) return;
01114   if (job->error()) {
01115     if ( job->error() != TDEIO::ERR_ACCESS_DENIED ) {
01116       // we suppress access denied messages because they are normally a result of
01117       // explicitely set ACLs. Do not save this information (e.g. setNoContent) so that
01118       // we notice when this changes
01119       account()->handleJobError( job, i18n("Error while querying the server status.") );
01120     }
01121     mContentState = imapNoInformation;
01122     emit folderComplete(this, false);
01123     close("checkvalidity");
01124   } else {
01125     TQCString cstr((*it).data.data(), (*it).data.size() + 1);
01126     int a = cstr.find("X-uidValidity: ");
01127     int b = cstr.find("\r\n", a);
01128     TQString uidv;
01129     if ( (b - a - 15) >= 0 )
01130         uidv = cstr.mid(a + 15, b - a - 15);
01131     a = cstr.find("X-Access: ");
01132     b = cstr.find("\r\n", a);
01133     TQString access;
01134     if ( (b - a - 10) >= 0 )
01135         access = cstr.mid(a + 10, b - a - 10);
01136     mReadOnly = access == "Read only";
01137     a = cstr.find("X-Count: ");
01138     b = cstr.find("\r\n", a);
01139     int exists = -1;
01140     bool ok = false;
01141     if ( (b - a - 9) >= 0 )
01142         exists = cstr.mid(a + 9, b - a - 9).toInt(&ok);
01143     if ( !ok ) exists = -1;
01144     a = cstr.find( "X-PermanentFlags: " );
01145     b = cstr.find( "\r\n", a );
01146     if ( a >= 0 && (b - a - 18) >= 0 )
01147       mPermanentFlags = cstr.mid( a + 18, b - a - 18 ).toInt(&ok);
01148     if ( !ok ) mPermanentFlags = 0;
01149     TQString startUid;
01150     if (uidValidity() != uidv)
01151     {
01152       // uidValidity changed
01153       kdDebug(5006) << k_funcinfo << "uidValidty changed from "
01154        << uidValidity() << " to " << uidv << endl;
01155       if ( !uidValidity().isEmpty() )
01156       {
01157         account()->ignoreJobsForFolder( folder() );
01158         mUidMetaDataMap.clear();
01159       }
01160       mLastUid = 0;
01161       setUidValidity(uidv);
01162       writeConfig();
01163     } else {
01164       if (!mCheckFlags)
01165         startUid = TQString::number(lastUid() + 1);
01166     }
01167     account()->removeJob(it);
01168     if ( mMailCheckProgressItem )
01169     {
01170       if ( startUid.isEmpty() ) {
01171         // flags for all messages are loaded
01172         mMailCheckProgressItem->setTotalItems( exists );
01173       } else {
01174         // only an approximation but doesn't hurt
01175         int remain = exists - count();
01176         if ( remain < 0 ) remain = 1;
01177         mMailCheckProgressItem->setTotalItems( remain );
01178       }
01179       mMailCheckProgressItem->setCompletedItems( 0 );
01180     }
01181     reallyGetFolder(startUid);
01182   }
01183 }
01184 
01185 //-----------------------------------------------------------------------------
01186 void KMFolderImap::getAndCheckFolder(bool force)
01187 {
01188   if (mNoContent)
01189     return getFolder(force);
01190 
01191   if ( account() )
01192     account()->processNewMailInFolder( folder() );
01193   if (force) {
01194     // force an update
01195     mCheckFlags = true;
01196   }
01197 }
01198 
01199 //-----------------------------------------------------------------------------
01200 void KMFolderImap::getFolder(bool force)
01201 {
01202   mGuessedUnreadMsgs = -1;
01203   if (mNoContent)
01204   {
01205     mContentState = imapFinished;
01206     emit folderComplete(this, true);
01207     return;
01208   }
01209   open("getfolder");
01210   mContentState = imapListingInProgress;
01211   if (force) {
01212     // force an update
01213     mCheckFlags = true;
01214   }
01215   checkValidity();
01216 }
01217 
01218 
01219 //-----------------------------------------------------------------------------
01220 void KMFolderImap::reallyGetFolder(const TQString &startUid)
01221 {
01222   KURL url = account()->getUrl();
01223   if ( account()->makeConnection() != ImapAccountBase::Connected )
01224   {
01225     mContentState = imapNoInformation;
01226     emit folderComplete(this, false);
01227     close("listfolder");
01228     return;
01229   }
01230   quiet(true);
01231   if (startUid.isEmpty())
01232   {
01233     if ( mMailCheckProgressItem )
01234       mMailCheckProgressItem->setStatus( i18n("Retrieving message status") );
01235     url.setPath(imapPath() + ";SECTION=UID FLAGS");
01236     TDEIO::SimpleJob *job = TDEIO::listDir(url, false);
01237     TDEIO::Scheduler::assignJobToSlave(account()->slave(), job);
01238     ImapAccountBase::jobData jd( url.url(), folder() );
01239     jd.cancellable = true;
01240     account()->insertJob(job, jd);
01241     connect(job, TQT_SIGNAL(result(TDEIO::Job *)),
01242             this, TQT_SLOT(slotListFolderResult(TDEIO::Job *)));
01243     connect(job, TQT_SIGNAL(entries(TDEIO::Job *, const TDEIO::UDSEntryList &)),
01244             this, TQT_SLOT(slotListFolderEntries(TDEIO::Job *,
01245             const TDEIO::UDSEntryList &)));
01246   } else {
01247     mContentState = imapDownloadInProgress;
01248     if ( mMailCheckProgressItem )
01249       mMailCheckProgressItem->setStatus( i18n("Retrieving messages") );
01250     url.setPath(imapPath() + ";UID=" + startUid
01251       + ":*;SECTION=ENVELOPE");
01252     TDEIO::SimpleJob *newJob = TDEIO::get(url, false, false);
01253     TDEIO::Scheduler::assignJobToSlave(account()->slave(), newJob);
01254     ImapAccountBase::jobData jd( url.url(), folder() );
01255     jd.cancellable = true;
01256     account()->insertJob(newJob, jd);
01257     connect(newJob, TQT_SIGNAL(result(TDEIO::Job *)),
01258             this, TQT_SLOT(slotGetLastMessagesResult(TDEIO::Job *)));
01259     connect(newJob, TQT_SIGNAL(data(TDEIO::Job *, const TQByteArray &)),
01260             this, TQT_SLOT(slotGetMessagesData(TDEIO::Job *, const TQByteArray &)));
01261   }
01262 }
01263 
01264 
01265 //-----------------------------------------------------------------------------
01266 void KMFolderImap::slotListFolderResult(TDEIO::Job * job)
01267 {
01268   ImapAccountBase::JobIterator it = account()->findJob(job);
01269   if ( it == account()->jobsEnd() ) return;
01270   TQString uids;
01271   if (job->error())
01272   {
01273     account()->handleJobError( job,
01274          i18n("Error while listing the contents of the folder %1.").arg( label() ) );
01275     account()->removeJob(it);
01276     finishMailCheck( "listfolder", imapNoInformation );
01277     return;
01278   }
01279   mCheckFlags = false;
01280   TQStringList::Iterator uid;
01281   /*
01282     The code below does the following:
01283     - for each mail in the local store and each entry we got from the server,
01284       compare the local uid with the one from the server and update the status
01285       flags of the mails
01286     - for all mails that are not already locally present, start a job which
01287       gets the envelope of each
01288     - remove all locally present mails if the server does not list them anymore
01289   */
01290   if ( count() ) {
01291     int idx = 0, c, serverFlags;
01292     ulong mailUid, serverUid;
01293     uid = (*it).items.begin();
01294     while ( idx < count() && uid != (*it).items.end() ) {
01295       KMMsgBase *msgBase = getMsgBase( idx );
01296       mailUid = msgBase->UID();
01297       // parse the uid from the server and the flags out of the list from
01298       // the server. Format: 1234, 1
01299       c = (*uid).find(",");
01300       serverUid = (*uid).left( c ).toLong();
01301       serverFlags = (*uid).mid( c+1 ).toInt();
01302       if ( mailUid < serverUid ) {
01303         removeMsg( idx, true );
01304       } else if ( mailUid == serverUid ) {
01305         // if this is a read only folder, ignore status updates from the server
01306         // since we can't write our status back our local version is what has to
01307         // be considered correct.
01308         if ( !mReadOnly || !GlobalSettings::allowLocalFlags() ) {
01309           int supportedFlags = mUploadAllFlags ? 31 : mPermanentFlags;
01310           if ( mReadOnly )
01311             supportedFlags = INT_MAX;
01312           flagsToStatus( msgBase, serverFlags, false, supportedFlags );
01313         } else
01314           seenFlagToStatus( msgBase, serverFlags, false );
01315         idx++;
01316         uid = (*it).items.remove(uid);
01317         if ( msgBase->getMsgSerNum() > 0 ) {
01318           saveMsgMetaData( static_cast<KMMessage*>(msgBase) );
01319         }
01320       }
01321       else break;  // happens only, if deleted mails reappear on the server
01322     }
01323     // remove all remaining entries in the local cache, they are no longer
01324     // present on the server
01325     while (idx < count()) removeMsg(idx, true);
01326   }
01327   // strip the flags from the list of uids, so it can be reused
01328   for (uid = (*it).items.begin(); uid != (*it).items.end(); ++uid)
01329     (*uid).truncate((*uid).find(","));
01330   ImapAccountBase::jobData jd( TQString(), (*it).parent );
01331   jd.total = (*it).items.count();
01332   if (jd.total == 0)
01333   {
01334     finishMailCheck( "listfolder", imapFinished );
01335     account()->removeJob(it);
01336     return;
01337   }
01338   if ( mMailCheckProgressItem )
01339   {
01340     // next step for the progressitem
01341     mMailCheckProgressItem->setCompletedItems( 0 );
01342     mMailCheckProgressItem->setTotalItems( jd.total );
01343     mMailCheckProgressItem->setProgress( 0 );
01344     mMailCheckProgressItem->setStatus( i18n("Retrieving messages") );
01345   }
01346 
01347   TQStringList sets;
01348   uid = (*it).items.begin();
01349   if (jd.total == 1) sets.append(*uid + ":" + *uid);
01350   else sets = makeSets( (*it).items );
01351   account()->removeJob(it); // don't use *it below
01352 
01353   // Now kick off the getting of envelopes for the new mails in the folder
01354   for (TQStringList::Iterator i = sets.begin(); i != sets.end(); ++i)
01355   {
01356     mContentState = imapDownloadInProgress;
01357     KURL url = account()->getUrl();
01358     url.setPath(imapPath() + ";UID=" + *i + ";SECTION=ENVELOPE");
01359     TDEIO::SimpleJob *newJob = TDEIO::get(url, false, false);
01360     jd.url = url.url();
01361     TDEIO::Scheduler::assignJobToSlave(account()->slave(), newJob);
01362     account()->insertJob(newJob, jd);
01363     connect(newJob, TQT_SIGNAL(result(TDEIO::Job *)),
01364         this, (i == sets.at(sets.count() - 1))
01365         ? TQT_SLOT(slotGetLastMessagesResult(TDEIO::Job *))
01366         : TQT_SLOT(slotGetMessagesResult(TDEIO::Job *)));
01367     connect(newJob, TQT_SIGNAL(data(TDEIO::Job *, const TQByteArray &)),
01368         this, TQT_SLOT(slotGetMessagesData(TDEIO::Job *, const TQByteArray &)));
01369   }
01370 }
01371 
01372 
01373 //-----------------------------------------------------------------------------
01374 void KMFolderImap::slotListFolderEntries(TDEIO::Job * job,
01375   const TDEIO::UDSEntryList & uds)
01376 {
01377   ImapAccountBase::JobIterator it = account()->findJob(job);
01378   if ( it == account()->jobsEnd() ) return;
01379   TQString mimeType, name;
01380   long int flags = 0;
01381   for (TDEIO::UDSEntryList::ConstIterator udsIt = uds.begin();
01382     udsIt != uds.end(); udsIt++)
01383   {
01384     for (TDEIO::UDSEntry::ConstIterator eIt = (*udsIt).begin();
01385       eIt != (*udsIt).end(); eIt++)
01386     {
01387       if ((*eIt).m_uds == TDEIO::UDS_NAME)
01388         name = (*eIt).m_str;
01389       else if ((*eIt).m_uds == TDEIO::UDS_MIME_TYPE)
01390         mimeType = (*eIt).m_str;
01391       else if ((*eIt).m_uds == TDEIO::UDS_ACCESS)
01392         flags = (*eIt).m_long;
01393     }
01394     if ((mimeType == "message/rfc822-imap" || mimeType == "message/rfc822") &&
01395         !(flags & 8)) {
01396       (*it).items.append(name + "," + TQString::number(flags));
01397       if ( mMailCheckProgressItem ) {
01398         mMailCheckProgressItem->incCompletedItems();
01399         mMailCheckProgressItem->updateProgress();
01400       }
01401     }
01402   }
01403 }
01404 
01405 
01406 // debugging helper
01407 //X static TQString flagsToString( int flags )
01408 //X {
01409 //X     TQString str("(");
01410 //X     if ( flags & 4 ) {
01411 //X         str += "\\Flagged ";
01412 //X     }
01413 //X     if ( flags & 2 ) {
01414 //X         str += "\\Answered ";
01415 //X     }
01416 //X     if ( flags & 1 ) {
01417 //X         str += "\\Seen";
01418 //X     }
01419 //X     str += ")";
01420 //X     return str;
01421 //X }
01422 
01423 //-----------------------------------------------------------------------------
01424 void KMFolderImap::flagsToStatus(KMMsgBase *msg, int flags, bool newMsg, int supportedFlags )
01425 {
01426   if ( !msg ) return;
01427 
01428   // see imap4/imapinfo.h for the magic numbers
01429   static const struct {
01430     const int imapFlag;
01431     const int kmFlag;
01432     const bool standardFlag;
01433   } imapFlagMap[] = {
01434     { 2, KMMsgStatusReplied, true },
01435     { 4, KMMsgStatusFlag, true },
01436     { 128, KMMsgStatusForwarded, false },
01437     { 256, KMMsgStatusTodo, false },
01438     { 512, KMMsgStatusWatched, false },
01439     { 1024, KMMsgStatusIgnored, false }
01440   };
01441   static const int numFlags = sizeof imapFlagMap / sizeof *imapFlagMap;
01442 
01443   const KMMsgStatus oldStatus = msg->status();
01444   for ( int i = 0; i < numFlags; ++i ) {
01445     if ( ( (supportedFlags & imapFlagMap[i].imapFlag) == 0 && (supportedFlags & 64) == 0 )
01446          && !imapFlagMap[i].standardFlag ) {
01447       continue;
01448     }
01449     if ( ((flags & imapFlagMap[i].imapFlag) > 0) != ((oldStatus & imapFlagMap[i].kmFlag) > 0) ) {
01450       msg->toggleStatus( imapFlagMap[i].kmFlag );
01451     }
01452   }
01453 
01454   seenFlagToStatus( msg, flags, newMsg );
01455 }
01456 
01457 void KMFolderImap::seenFlagToStatus(KMMsgBase * msg, int flags, bool newMsg)
01458 {
01459   if ( !msg ) return;
01460 
01461   const KMMsgStatus oldStatus = msg->status();
01462   if ( (flags & 1) && (oldStatus & KMMsgStatusOld) == 0 )
01463     msg->setStatus( KMMsgStatusOld );
01464 
01465   // In case the message does not have the seen flag set, override our local
01466   // notion that it is read. Otherwise the count of unread messages and the
01467   // number of messages which actually show up as read can go out of sync.
01468   if ( msg->isOfUnknownStatus() || (!(flags&1) && !(oldStatus&(KMMsgStatusNew|KMMsgStatusUnread)) ) ) {
01469     if (newMsg) {
01470       if ( (oldStatus & KMMsgStatusNew) == 0 )
01471         msg->setStatus( KMMsgStatusNew );
01472     } else {
01473       if ( (oldStatus & KMMsgStatusUnread) == 0 )
01474         msg->setStatus( KMMsgStatusUnread );
01475     }
01476   }
01477 }
01478 
01479 
01480 //-----------------------------------------------------------------------------
01481 TQString KMFolderImap::statusToFlags(KMMsgStatus status, int supportedFlags)
01482 {
01483   TQString flags;
01484   if (status & KMMsgStatusDeleted)
01485     flags = "\\DELETED";
01486   else {
01487     if (status & KMMsgStatusOld || status & KMMsgStatusRead)
01488       flags = "\\SEEN ";
01489     if (status & KMMsgStatusReplied)
01490       flags += "\\ANSWERED ";
01491     if (status & KMMsgStatusFlag)
01492       flags += "\\FLAGGED ";
01493     // non standard flags
01494     if ( (status & KMMsgStatusForwarded) && ((supportedFlags & 64) || (supportedFlags & 128)) )
01495       flags += "$FORWARDED ";
01496     if ( (status & KMMsgStatusTodo) && ((supportedFlags & 64) || (supportedFlags & 256)) )
01497       flags += "$TODO ";
01498     if ( (status & KMMsgStatusWatched) && ((supportedFlags & 64) || (supportedFlags & 512)) )
01499       flags += "$WATCHED ";
01500     if ( (status & KMMsgStatusIgnored) && ((supportedFlags & 64) || (supportedFlags & 1024)) )
01501       flags += "$IGNORED ";
01502   }
01503 
01504   return flags.simplifyWhiteSpace();
01505 }
01506 
01507 //-------------------------------------------------------------
01508 void
01509 KMFolderImap::ignoreJobsForMessage( KMMessage* msg )
01510 {
01511   if ( !msg || msg->transferInProgress() ||
01512        !msg->parent() || msg->parent()->folderType() != KMFolderTypeImap )
01513     return;
01514   KMAcctImap *account;
01515   if ( !(account = static_cast<KMFolderImap*>(msg->storage())->account()) )
01516     return;
01517 
01518   account->ignoreJobsForMessage( msg );
01519 }
01520 
01521 //-----------------------------------------------------------------------------
01522 void KMFolderImap::slotGetMessagesData(TDEIO::Job * job, const TQByteArray & data)
01523 {
01524   if ( data.isEmpty() ) return; // optimization
01525   ImapAccountBase::JobIterator it = account()->findJob(job);
01526   if ( it == account()->jobsEnd() ) return;
01527   (*it).cdata += TQCString(data, data.size() + 1);
01528   int pos = (*it).cdata.find("\r\n--IMAPDIGEST");
01529   if ( pos == -1 ) {
01530     // if we do not find the pattern in the complete string we will not find
01531     // it in a substring.
01532     return;
01533   }
01534   if (pos > 0)
01535   {
01536     int p = (*it).cdata.find("\r\nX-uidValidity:");
01537     if (p != -1) setUidValidity((*it).cdata
01538       .mid(p + 17, (*it).cdata.find("\r\n", p+1) - p - 17));
01539     int c = (*it).cdata.find("\r\nX-Count:");
01540     if ( c != -1 )
01541     {
01542       bool ok;
01543       int exists = (*it).cdata.mid( c+10,
01544           (*it).cdata.find("\r\n", c+1) - c-10 ).toInt(&ok);
01545       if ( ok && exists < count() ) {
01546         kdDebug(5006) << "KMFolderImap::slotGetMessagesData - server has less messages (" <<
01547           exists << ") then folder (" << count() << "), so reload" << endl;
01548         open("getMessage");
01549         reallyGetFolder( TQString() );
01550         (*it).cdata.remove(0, pos);
01551         return;
01552       } else if ( ok ) {
01553         int delta = exists - count();
01554         if ( mMailCheckProgressItem ) {
01555           mMailCheckProgressItem->setTotalItems( delta );
01556         }
01557       }
01558     }
01559     (*it).cdata.remove(0, pos);
01560   }
01561   pos = (*it).cdata.find("\r\n--IMAPDIGEST", 1);
01562   int flags;
01563   while (pos >= 0)
01564   {
01565     KMMessage *msg = new KMMessage;
01566     msg->setComplete( false );
01567     msg->setReadyToShow( false );
01568     // nothing between the boundaries, older UWs do that
01569     if ( pos != 14 ) {
01570       msg->fromString( (*it).cdata.mid(16, pos - 16) );
01571       flags = msg->headerField("X-Flags").toInt();
01572       ulong uid = msg->UID();
01573       KMMsgMetaData *md =  0;
01574       if ( mUidMetaDataMap.find( uid ) ) {
01575           md =  mUidMetaDataMap[uid];
01576       }
01577       ulong serNum = 0;
01578       if ( md ) {
01579         serNum = md->serNum();
01580       }
01581       bool ok = true;
01582       if ( uid <= lastUid() && serNum > 0 ) {
01583         // the UID is already known so no need to create it
01584         ok = false;
01585       }
01586       // deleted flag
01587       if ( flags & 8 )
01588         ok = false;
01589       if ( !ok ) {
01590         delete msg;
01591         msg = 0;
01592       } else {
01593         if ( serNum > 0 ) {
01594           // assign the sernum from the cache
01595           msg->setMsgSerNum( serNum );
01596         }
01597         // Transfer the status, if it is cached.
01598         if ( md ) {
01599           msg->setStatus( md->status() );
01600         } else if ( !account()->hasCapability("uidplus") ) {
01601           // see if we have cached the msgIdMD5 and get the status +
01602           // serial number from there
01603           TQString id = msg->msgIdMD5();
01604           if ( mMetaDataMap.find( id ) ) {
01605             md =  mMetaDataMap[id];
01606             msg->setStatus( md->status() );
01607             if ( md->serNum() != 0 && serNum == 0 ) {
01608               msg->setMsgSerNum( md->serNum() );
01609             }
01610             mMetaDataMap.remove( id );
01611             delete md;
01612           }
01613         }
01614         KMFolderMbox::addMsg(msg, 0);
01615         // Merge with the flags from the server.
01616         flagsToStatus((KMMsgBase*)msg, flags, true, mUploadAllFlags ? 31 : mPermanentFlags);
01617         // set the correct size
01618         msg->setMsgSizeServer( msg->headerField("X-Length").toUInt() );
01619         msg->setUID(uid);
01620         if ( msg->getMsgSerNum() > 0 ) {
01621           saveMsgMetaData( msg );
01622         }
01623         // Filter messages that have arrived in the inbox folder
01624         if ( folder()->isSystemFolder() && imapPath() == "/INBOX/"
01625             && kmkernel->filterMgr()->atLeastOneIncomingFilterAppliesTo( account()->id() ) )
01626             account()->execFilters( msg->getMsgSerNum() );
01627 
01628         if ( count() > 1 ) {
01629           unGetMsg(count() - 1);
01630         }
01631         mLastUid = uid;
01632         if ( mMailCheckProgressItem ) {
01633           mMailCheckProgressItem->incCompletedItems();
01634           mMailCheckProgressItem->updateProgress();
01635         }
01636       }
01637     }
01638     (*it).cdata.remove(0, pos);
01639     (*it).done++;
01640     pos = (*it).cdata.find("\r\n--IMAPDIGEST", 1);
01641   } // while
01642 }
01643 
01644 //-------------------------------------------------------------
01645 FolderJob*
01646 KMFolderImap::doCreateJob( KMMessage *msg, FolderJob::JobType jt,
01647                            KMFolder *folder, TQString partSpecifier,
01648                            const AttachmentStrategy *as ) const
01649 {
01650   KMFolderImap* kmfi = folder? dynamic_cast<KMFolderImap*>(folder->storage()) : 0;
01651   if ( jt == FolderJob::tGetMessage && partSpecifier == "STRUCTURE" &&
01652        account() && account()->loadOnDemand() &&
01653        ( msg->msgSizeServer() > 5000 || msg->msgSizeServer() == 0 ) &&
01654        ( msg->signatureState() == KMMsgNotSigned ||
01655          msg->signatureState() == KMMsgSignatureStateUnknown ) &&
01656        ( msg->encryptionState() == KMMsgNotEncrypted ||
01657          msg->encryptionState() == KMMsgEncryptionStateUnknown ) )
01658   {
01659     // load-on-demand: retrieve the BODYSTRUCTURE and to speed things up also the headers
01660     // this is not activated for small or signed messages
01661     ImapJob *job = new ImapJob( msg, jt, kmfi, "HEADER" );
01662     job->start();
01663     ImapJob *job2 = new ImapJob( msg, jt, kmfi, "STRUCTURE", as );
01664     job2->start();
01665     job->setParentFolder( this );
01666     return job;
01667   } else {
01668     // download complete message or part (attachment)
01669     if ( partSpecifier == "STRUCTURE" ) // hide from outside
01670       partSpecifier = TQString();
01671 
01672     ImapJob *job = new ImapJob( msg, jt, kmfi, partSpecifier );
01673     job->setParentFolder( this );
01674     return job;
01675   }
01676 }
01677 
01678 //-------------------------------------------------------------
01679 FolderJob*
01680 KMFolderImap::doCreateJob( TQPtrList<KMMessage>& msgList, const TQString& sets,
01681                            FolderJob::JobType jt, KMFolder *folder ) const
01682 {
01683   KMFolderImap* kmfi = dynamic_cast<KMFolderImap*>(folder->storage());
01684   ImapJob *job = new ImapJob( msgList, sets, jt, kmfi );
01685   job->setParentFolder( this );
01686   return job;
01687 }
01688 
01689 //-----------------------------------------------------------------------------
01690 void KMFolderImap::getMessagesResult(TDEIO::Job * job, bool lastSet)
01691 {
01692   ImapAccountBase::JobIterator it = account()->findJob(job);
01693   if ( it == account()->jobsEnd() ) return;
01694   if (job->error()) {
01695     account()->handleJobError( job, i18n("Error while retrieving messages.") );
01696     finishMailCheck( "getMessage", imapNoInformation );
01697     return;
01698   }
01699   if (lastSet) {
01700     finishMailCheck( "getMessage", imapFinished );
01701     account()->removeJob(it);
01702   }
01703 }
01704 
01705 
01706 //-----------------------------------------------------------------------------
01707 void KMFolderImap::slotGetLastMessagesResult(TDEIO::Job * job)
01708 {
01709   getMessagesResult(job, true);
01710 }
01711 
01712 
01713 //-----------------------------------------------------------------------------
01714 void KMFolderImap::slotGetMessagesResult(TDEIO::Job * job)
01715 {
01716   getMessagesResult(job, false);
01717 }
01718 
01719 
01720 //-----------------------------------------------------------------------------
01721 void KMFolderImap::createFolder(const TQString &name, const TQString& parentPath,
01722                                 bool askUser)
01723 {
01724   kdDebug(5006) << "KMFolderImap::createFolder - name=" << name << ",parent=" <<
01725     parentPath << ",askUser=" << askUser << endl;
01726   if ( account()->makeConnection() != ImapAccountBase::Connected ) {
01727     kdWarning(5006) << "KMFolderImap::createFolder - got no connection" << endl;
01728     return;
01729   }
01730   KURL url = account()->getUrl();
01731   TQString parent = ( parentPath.isEmpty() ? imapPath() : parentPath );
01732   TQString path = account()->createImapPath( parent, name );
01733   if ( askUser ) {
01734     path += "/;INFO=ASKUSER";
01735   }
01736   url.setPath( path );
01737 
01738   TDEIO::SimpleJob *job = TDEIO::mkdir(url);
01739   TDEIO::Scheduler::assignJobToSlave(account()->slave(), job);
01740   ImapAccountBase::jobData jd( url.url(), folder() );
01741   jd.items = name;
01742   account()->insertJob(job, jd);
01743   connect(job, TQT_SIGNAL(result(TDEIO::Job *)),
01744           this, TQT_SLOT(slotCreateFolderResult(TDEIO::Job *)));
01745 }
01746 
01747 
01748 //-----------------------------------------------------------------------------
01749 void KMFolderImap::slotCreateFolderResult(TDEIO::Job * job)
01750 {
01751   ImapAccountBase::JobIterator it = account()->findJob(job);
01752   if ( it == account()->jobsEnd() ) return;
01753 
01754   TQString name;
01755   if ( it.data().items.count() > 0 )
01756     name = it.data().items.first();
01757 
01758   if (job->error())
01759   {
01760     if ( job->error() == TDEIO::ERR_COULD_NOT_MKDIR ) {
01761       // Creating a folder failed, remove it from the tree.
01762       account()->listDirectory( );
01763     }
01764     account()->handleJobError( job, i18n("Error while creating a folder.") );
01765     emit folderCreationResult( name, false );
01766   } else {
01767     listDirectory();
01768     account()->removeJob(job);
01769     emit folderCreationResult( name, true );
01770   }
01771 }
01772 
01773 
01774 //-----------------------------------------------------------------------------
01775 static TQTextCodec *sUtf7Codec = 0;
01776 
01777 TQTextCodec * KMFolderImap::utf7Codec()
01778 {
01779   if (!sUtf7Codec) sUtf7Codec = TQTextCodec::codecForName("utf-7");
01780   return sUtf7Codec;
01781 }
01782 
01783 
01784 //-----------------------------------------------------------------------------
01785 TQString KMFolderImap::encodeFileName(const TQString &name)
01786 {
01787   TQString result = utf7Codec()->fromUnicode(name);
01788   return KURL::encode_string_no_slash(result);
01789 }
01790 
01791 
01792 //-----------------------------------------------------------------------------
01793 TQString KMFolderImap::decodeFileName(const TQString &name)
01794 {
01795   TQString result = KURL::decode_string(name);
01796   return utf7Codec()->toUnicode(result.latin1());
01797 }
01798 
01799 //-----------------------------------------------------------------------------
01800 bool KMFolderImap::autoExpunge()
01801 {
01802   if (account())
01803     return account()->autoExpunge();
01804 
01805   return false;
01806 }
01807 
01808 
01809 //-----------------------------------------------------------------------------
01810 void KMFolderImap::slotSimpleData(TDEIO::Job * job, const TQByteArray & data)
01811 {
01812   if ( data.isEmpty() ) return; // optimization
01813   ImapAccountBase::JobIterator it = account()->findJob(job);
01814   if ( it == account()->jobsEnd() ) return;
01815   TQBuffer buff((*it).data);
01816   buff.open(IO_WriteOnly | IO_Append);
01817   buff.writeBlock(data.data(), data.size());
01818   buff.close();
01819 }
01820 
01821 //-----------------------------------------------------------------------------
01822 void KMFolderImap::deleteMessage(KMMessage * msg)
01823 {
01824   mUidMetaDataMap.remove( msg->UID() );
01825   mMetaDataMap.remove( msg->msgIdMD5() );
01826   KURL url = account()->getUrl();
01827   KMFolderImap *msg_parent = static_cast<KMFolderImap*>(msg->storage());
01828   ulong uid = msg->UID();
01829   /* If the uid is empty the delete job below will nuke all mail in the
01830      folder, so we better safeguard against that. See ::expungeFolder, as
01831      to why. :( */
01832   if ( uid == 0 ) {
01833      kdDebug( 5006 ) << "KMFolderImap::deleteMessage: Attempt to delete "
01834                         "an empty UID. Aborting."  << endl;
01835      return;
01836   }
01837   url.setPath(msg_parent->imapPath() + ";UID=" + TQString::number(uid) );
01838   if ( account()->makeConnection() != ImapAccountBase::Connected )
01839     return;
01840   TDEIO::SimpleJob *job = TDEIO::file_delete(url, false);
01841   TDEIO::Scheduler::assignJobToSlave(account()->slave(), job);
01842   ImapAccountBase::jobData jd( url.url(), 0 );
01843   account()->insertJob(job, jd);
01844   connect(job, TQT_SIGNAL(result(TDEIO::Job *)),
01845           account(), TQT_SLOT(slotSimpleResult(TDEIO::Job *)));
01846 }
01847 
01848 void KMFolderImap::deleteMessage(const TQPtrList<KMMessage>& msgList)
01849 {
01850   TQPtrListIterator<KMMessage> it( msgList );
01851   KMMessage *msg;
01852   while ( (msg = it.current()) != 0 ) {
01853     ++it;
01854     mUidMetaDataMap.remove( msg->UID() );
01855     mMetaDataMap.remove( msg->msgIdMD5() );
01856   }
01857 
01858   TQValueList<ulong> uids;
01859   getUids(msgList, uids);
01860   TQStringList sets = makeSets(uids);
01861 
01862   KURL url = account()->getUrl();
01863   KMFolderImap *msg_parent = static_cast<KMFolderImap*>(msgList.getFirst()->storage());
01864   for ( TQStringList::Iterator it = sets.begin(); it != sets.end(); ++it )
01865   {
01866     TQString uid = *it;
01867     // Don't delete with no uid, that nukes the folder. Should not happen, but
01868     // better safe than sorry.
01869     if ( uid.isEmpty() ) continue;
01870     url.setPath(msg_parent->imapPath() + ";UID=" + uid);
01871     if ( account()->makeConnection() != ImapAccountBase::Connected )
01872       return;
01873     TDEIO::SimpleJob *job = TDEIO::file_delete(url, false);
01874     TDEIO::Scheduler::assignJobToSlave(account()->slave(), job);
01875     ImapAccountBase::jobData jd( url.url(), 0 );
01876     account()->insertJob(job, jd);
01877     connect(job, TQT_SIGNAL(result(TDEIO::Job *)),
01878         account(), TQT_SLOT(slotSimpleResult(TDEIO::Job *)));
01879   }
01880 }
01881 
01882 //-----------------------------------------------------------------------------
01883 void KMFolderImap::setStatus(int idx, KMMsgStatus status, bool toggle)
01884 {
01885   TQValueList<int> ids; ids.append(idx);
01886   setStatus(ids, status, toggle);
01887 }
01888 
01889 void KMFolderImap::setStatus(TQValueList<int>& _ids, KMMsgStatus status, bool toggle)
01890 {
01891   FolderStorage::setStatus(_ids, status, toggle);
01892   TQValueList<int> ids;
01893   if ( mUploadAllFlags ) {
01894     kdDebug(5006) << k_funcinfo << "Migrating all flags to the server" << endl;
01895     ids.clear();
01896     for ( int i = 0; i < count(); ++i )
01897       ids << i;
01898     mUploadAllFlags = false;
01899   } else {
01900     ids = _ids;
01901   }
01902 
01903   /* The status has been already set in the local index. Update the flags on
01904    * the server. To avoid doing that for each message individually, group them
01905    * by the status string they will be assigned and make sets for each of those
01906    * groups of mails. This is necessary because the imap tdeio_slave status job
01907    * does not append flags but overwrites them. Example:
01908    *
01909    * 2 important mails and 3 unimportant mail, all unread. Mark all as read calls
01910    * this method with a list of uids. The 2 important mails need to get the string
01911    * \SEEN \FLAGGED while the others need to get just \SEEN. Build sets for each
01912    * of those and sort them, so the server can handle them efficiently. */
01913 
01914   if ( mReadOnly ) { // mUserRights is not available here
01915     // FIXME duplicated code in KMFolderCachedImap
01916     TQValueList<ulong> seenUids, unseenUids;
01917     for ( TQValueList<int>::ConstIterator it = ids.constBegin(); it != ids.constEnd(); ++it ) {
01918       KMMessage *msg = 0;
01919       bool unget = !isMessage(*it);
01920       msg = getMsg(*it);
01921       if (!msg) continue;
01922       if ( msg->status() & KMMsgStatusOld || msg->status() & KMMsgStatusRead )
01923         seenUids.append( msg->UID() );
01924       else
01925         unseenUids.append( msg->UID() );
01926       if (unget) unGetMsg(*it);
01927     }
01928     if ( !seenUids.isEmpty() ) {
01929       TQStringList sets = KMFolderImap::makeSets( seenUids, true );
01930       for( TQStringList::Iterator it = sets.begin(); it != sets.end(); ++it ) {
01931         TQString imappath = imapPath() + ";UID=" + ( *it );
01932         account()->setImapSeenStatus( folder(), imappath, true );
01933       }
01934     }
01935     if ( !unseenUids.isEmpty() ) {
01936       TQStringList sets = KMFolderImap::makeSets( unseenUids, true );
01937       for( TQStringList::Iterator it = sets.begin(); it != sets.end(); ++it ) {
01938         TQString imappath = imapPath() + ";UID=" + ( *it );
01939         account()->setImapSeenStatus( folder(), imappath, false );
01940       }
01941     }
01942     return;
01943   }
01944 
01945   TQMap< TQString, TQStringList > groups;
01946   for ( TQValueList<int>::Iterator it = ids.begin(); it != ids.end(); ++it ) {
01947     KMMessage *msg = 0;
01948     bool unget = !isMessage(*it);
01949     msg = getMsg(*it);
01950     if (!msg) continue;
01951     TQString flags = statusToFlags(msg->status(), mPermanentFlags);
01952     // Collect uids for each type of flags.
01953     groups[flags].append(TQString::number(msg->UID()));
01954     if (unget) unGetMsg(*it);
01955   }
01956   TQMapIterator< TQString, TQStringList > dit;
01957   for ( dit = groups.begin(); dit != groups.end(); ++dit ) {
01958      TQCString flags = dit.key().latin1();
01959      TQStringList sets = makeSets( (*dit), true );
01960      // Send off a status setting job for each set.
01961      for (  TQStringList::Iterator slit = sets.begin(); slit != sets.end(); ++slit ) {
01962        TQString imappath = imapPath() + ";UID=" + ( *slit );
01963        account()->setImapStatus(folder(), imappath, flags);
01964      }
01965   }
01966   if ( mContentState == imapListingInProgress ) {
01967     // we're currently get'ing this folder
01968     // to make sure that we get the latest flags abort the current listing and
01969     // create a new one
01970     kdDebug(5006) << "Set status during folder listing, restarting listing." << endl;
01971     disconnect(this, TQT_SLOT(slotListFolderResult(TDEIO::Job *)));
01972     quiet( false );
01973     reallyGetFolder( TQString() );
01974   }
01975 }
01976 
01977 //-----------------------------------------------------------------------------
01978 TQStringList KMFolderImap::makeSets(const TQStringList& uids, bool sort)
01979 {
01980   TQValueList<ulong> tmp;
01981   for ( TQStringList::ConstIterator it = uids.begin(); it != uids.end(); ++it )
01982     tmp.append( (*it).toInt() );
01983   return makeSets(tmp, sort);
01984 }
01985 
01986 TQStringList KMFolderImap::makeSets( TQValueList<ulong>& uids, bool sort )
01987 {
01988   TQStringList sets;
01989   TQString set;
01990 
01991   if (uids.size() == 1)
01992   {
01993     sets.append(TQString::number(uids.first()));
01994     return sets;
01995   }
01996 
01997   if (sort) qHeapSort(uids);
01998 
01999   ulong last = 0;
02000   // needed to make a uid like 124 instead of 124:124
02001   bool inserted = false;
02002   /* iterate over uids and build sets like 120:122,124,126:150 */
02003   for ( TQValueList<ulong>::Iterator it = uids.begin(); it != uids.end(); ++it )
02004   {
02005     if (it == uids.begin() || set.isEmpty()) {
02006       set = TQString::number(*it);
02007       inserted = true;
02008     } else
02009     {
02010       if (last+1 != *it)
02011       {
02012         // end this range
02013         if (inserted)
02014           set += ',' + TQString::number(*it);
02015         else
02016           set += ':' + TQString::number(last) + ',' + TQString::number(*it);
02017         inserted = true;
02018         if (set.length() > 100)
02019         {
02020           // just in case the server has a problem with longer lines..
02021           sets.append(set);
02022           set = "";
02023         }
02024       } else {
02025         inserted = false;
02026       }
02027     }
02028     last = *it;
02029   }
02030   // last element
02031   if (!inserted)
02032     set += ':' + TQString::number(uids.last());
02033 
02034   if (!set.isEmpty()) sets.append(set);
02035 
02036   return sets;
02037 }
02038 
02039 //-----------------------------------------------------------------------------
02040 void KMFolderImap::getUids(TQValueList<int>& ids, TQValueList<ulong>& uids)
02041 {
02042   KMMsgBase *msg = 0;
02043   // get the uids
02044   for ( TQValueList<int>::Iterator it = ids.begin(); it != ids.end(); ++it )
02045   {
02046     msg = getMsgBase(*it);
02047     if (!msg) continue;
02048     uids.append(msg->UID());
02049   }
02050 }
02051 
02052 void KMFolderImap::getUids(const TQPtrList<KMMessage>& msgList, TQValueList<ulong>& uids)
02053 {
02054   KMMessage *msg = 0;
02055 
02056   TQPtrListIterator<KMMessage> it( msgList );
02057   while ( (msg = it.current()) != 0 ) {
02058     ++it;
02059     if ( msg->UID() > 0 ) {
02060       uids.append( msg->UID() );
02061     }
02062   }
02063 }
02064 
02065 //-----------------------------------------------------------------------------
02066 void KMFolderImap::expungeFolder(KMFolderImap * aFolder, bool quiet)
02067 {
02068   aFolder->setNeedsCompacting(false);
02069   KURL url = account()->getUrl();
02070   url.setPath(aFolder->imapPath() + ";UID=*");
02071   if ( account()->makeConnection() != ImapAccountBase::Connected )
02072     return;
02073   TDEIO::SimpleJob *job = TDEIO::file_delete(url, false);
02074   TDEIO::Scheduler::assignJobToSlave(account()->slave(), job);
02075   ImapAccountBase::jobData jd( url.url(), 0 );
02076   jd.quiet = quiet;
02077   account()->insertJob(job, jd);
02078   connect(job, TQT_SIGNAL(result(TDEIO::Job *)),
02079           account(), TQT_SLOT(slotSimpleResult(TDEIO::Job *)));
02080 }
02081 
02082 //-----------------------------------------------------------------------------
02083 void KMFolderImap::slotProcessNewMail( int errorCode, const TQString &errorMsg )
02084 {
02085   Q_UNUSED( errorMsg );
02086   disconnect( account(), TQT_SIGNAL( connectionResult(int, const TQString&) ),
02087               this, TQT_SLOT( slotProcessNewMail(int, const TQString&) ) );
02088   if ( !errorCode )
02089     processNewMail( false );
02090   else
02091     emit numUnreadMsgsChanged( folder() );
02092 }
02093 
02094 //-----------------------------------------------------------------------------
02095 bool KMFolderImap::processNewMail(bool)
02096 {
02097    // a little safety
02098   if ( !account() ) {
02099     kdDebug(5006) << "KMFolderImap::processNewMail - account is null!" << endl;
02100     return false;
02101   }
02102   if ( imapPath().isEmpty() ) {
02103     kdDebug(5006) << "KMFolderImap::processNewMail - imapPath of " << name() << " is empty!" << endl;
02104     // remove it locally
02105     setAlreadyRemoved( true );
02106     kmkernel->imapFolderMgr()->remove( folder() );
02107     return false;
02108   }
02109   // check the connection
02110   if ( account()->makeConnection() == ImapAccountBase::Error ) {
02111     kdDebug(5006) << "KMFolderImap::processNewMail - got no connection!" << endl;
02112     return false;
02113   } else if ( account()->makeConnection() == ImapAccountBase::Connecting )
02114   {
02115     // wait
02116     kdDebug(5006) << "KMFolderImap::processNewMail - waiting for connection: " << label() << endl;
02117     connect( account(), TQT_SIGNAL( connectionResult(int, const TQString&) ),
02118         this, TQT_SLOT( slotProcessNewMail(int, const TQString&) ) );
02119     return true;
02120   }
02121   KURL url = account()->getUrl();
02122   if (mReadOnly)
02123     url.setPath(imapPath() + ";SECTION=UIDNEXT");
02124   else
02125     url.setPath(imapPath() + ";SECTION=UNSEEN");
02126 
02127   mMailCheckProgressItem = ProgressManager::createProgressItem(
02128               "MailCheckAccount" + account()->name(),
02129               "MailCheck" + folder()->prettyURL(),
02130               TQStyleSheet::escape( folder()->prettyURL() ),
02131               i18n("updating message counts"),
02132               false,
02133               account()->useSSL() || account()->useTLS() );
02134 
02135   TDEIO::SimpleJob *job = TDEIO::stat(url, false);
02136   TDEIO::Scheduler::assignJobToSlave(account()->slave(), job);
02137   ImapAccountBase::jobData jd(url.url(), folder() );
02138   jd.cancellable = true;
02139   account()->insertJob(job, jd);
02140   connect(job, TQT_SIGNAL(result(TDEIO::Job *)),
02141           TQT_SLOT(slotStatResult(TDEIO::Job *)));
02142   return true;
02143 }
02144 
02145 
02146 //-----------------------------------------------------------------------------
02147 void KMFolderImap::slotStatResult(TDEIO::Job * job)
02148 {
02149   slotCompleteMailCheckProgress();
02150   ImapAccountBase::JobIterator it = account()->findJob(job);
02151   if ( it == account()->jobsEnd() ) return;
02152   account()->removeJob(it);
02153   if (job->error())
02154   {
02155     account()->handleJobError( job, i18n("Error while getting folder information.") );
02156   } else {
02157     TDEIO::UDSEntry uds = static_cast<TDEIO::StatJob*>(job)->statResult();
02158     for (TDEIO::UDSEntry::ConstIterator it = uds.begin(); it != uds.end(); it++)
02159     {
02160       if ((*it).m_uds == TDEIO::UDS_SIZE)
02161       {
02162         if (mReadOnly)
02163         {
02164           mGuessedUnreadMsgs = -1;
02165           mGuessedUnreadMsgs = countUnread() + (*it).m_long - lastUid() - 1;
02166           if (mGuessedUnreadMsgs < 0) mGuessedUnreadMsgs = 0;
02167         } else {
02168           mGuessedUnreadMsgs = (*it).m_long;
02169         }
02170       }
02171     }
02172   }
02173 }
02174 
02175 //-----------------------------------------------------------------------------
02176 int KMFolderImap::create()
02177 {
02178   readConfig();
02179   mUnreadMsgs = -1;
02180   return KMFolderMbox::create();
02181 }
02182 
02183 TQValueList<ulong> KMFolderImap::splitSets(const TQString uids)
02184 {
02185   TQValueList<ulong> uidlist;
02186 
02187   // ex: 1205,1204,1203,1202,1236:1238
02188   TQString buffer = TQString();
02189   int setstart = -1;
02190   // iterate over the uids
02191   for (uint i = 0; i < uids.length(); i++)
02192   {
02193     TQChar chr = uids[i];
02194     if (chr == ',')
02195     {
02196       if (setstart > -1)
02197       {
02198         // a range (uid:uid) was before
02199         for (int j = setstart; j <= buffer.toInt(); j++)
02200         {
02201           uidlist.append(j);
02202         }
02203         setstart = -1;
02204       } else {
02205         // single uid
02206         uidlist.append(buffer.toInt());
02207       }
02208       buffer = "";
02209     } else if (chr == ':') {
02210       // remember the start of the range
02211       setstart = buffer.toInt();
02212       buffer = "";
02213     } else if (chr.category() == TQChar::Number_DecimalDigit) {
02214       // digit
02215       buffer += chr;
02216     } else {
02217       // ignore
02218     }
02219   }
02220   // process the last data
02221   if (setstart > -1)
02222   {
02223     for (int j = setstart; j <= buffer.toInt(); j++)
02224     {
02225       uidlist.append(j);
02226     }
02227   } else {
02228     uidlist.append(buffer.toInt());
02229   }
02230 
02231   return uidlist;
02232 }
02233 
02234 //-----------------------------------------------------------------------------
02235 int KMFolderImap::expungeContents()
02236 {
02237   // nuke the local cache
02238   int rc = KMFolderMbox::expungeContents();
02239 
02240   // set the deleted flag for all messages in the folder
02241   KURL url = account()->getUrl();
02242   url.setPath( imapPath() + ";UID=1:*");
02243   if ( account()->makeConnection() == ImapAccountBase::Connected )
02244   {
02245     TDEIO::SimpleJob *job = TDEIO::file_delete(url, false);
02246     TDEIO::Scheduler::assignJobToSlave(account()->slave(), job);
02247     ImapAccountBase::jobData jd( url.url(), 0 );
02248     jd.quiet = true;
02249     account()->insertJob(job, jd);
02250     connect(job, TQT_SIGNAL(result(TDEIO::Job *)),
02251             account(), TQT_SLOT(slotSimpleResult(TDEIO::Job *)));
02252   }
02253   /* Is the below correct? If we are expunging (in the folder sense, not the imap sense),
02254      why delete but not (imap-)expunge? Since the folder is not active there is no concept
02255      of "leaving the folder", so the setting really has little to do with it. */
02256   // if ( autoExpunge() )
02257     expungeFolder(this, true);
02258   getFolder();
02259 
02260   return rc;
02261 }
02262 
02263 //-----------------------------------------------------------------------------
02264 void
02265 KMFolderImap::setUserRights( unsigned int userRights, KMail::ACLJobs::ACLFetchState userRightsState )
02266 {
02267   mUserRights = userRights;
02268   mUserRightsState = userRightsState;
02269 }
02270 
02271 //-----------------------------------------------------------------------------
02272 void KMFolderImap::slotCompleteMailCheckProgress()
02273 {
02274   if ( mMailCheckProgressItem ) {
02275     mMailCheckProgressItem->setComplete();
02276     mMailCheckProgressItem = 0;
02277     emit numUnreadMsgsChanged( folder() );
02278   }
02279 }
02280 
02281 //-----------------------------------------------------------------------------
02282 void KMFolderImap::setSubfolderState( imapState state )
02283 {
02284   mSubfolderState = state;
02285   if ( state == imapNoInformation && folder()->child() )
02286   {
02287     // pass through to children
02288     KMFolderNode* node;
02289     TQPtrListIterator<KMFolderNode> it( *folder()->child() );
02290     for ( ; (node = it.current()); )
02291     {
02292       ++it;
02293       if (node->isDir()) continue;
02294       KMFolder *folder = static_cast<KMFolder*>(node);
02295       static_cast<KMFolderImap*>(folder->storage())->setSubfolderState( state );
02296     }
02297   }
02298 }
02299 
02300 //-----------------------------------------------------------------------------
02301 void KMFolderImap::setIncludeInMailCheck( bool check )
02302 {
02303   bool changed = ( mCheckMail != check );
02304   mCheckMail = check;
02305   if ( changed )
02306     account()->slotUpdateFolderList();
02307 }
02308 
02309 //-----------------------------------------------------------------------------
02310 void KMFolderImap::setAlreadyRemoved( bool removed )
02311 {
02312   mAlreadyRemoved = removed;
02313   if ( folder()->child() )
02314   {
02315     // pass through to childs
02316     KMFolderNode* node;
02317     TQPtrListIterator<KMFolderNode> it( *folder()->child() );
02318     for ( ; (node = it.current()); )
02319     {
02320       ++it;
02321       if (node->isDir()) continue;
02322       KMFolder *folder = static_cast<KMFolder*>(node);
02323       static_cast<KMFolderImap*>(folder->storage())->setAlreadyRemoved( removed );
02324     }
02325   }
02326 }
02327 
02328 void KMFolderImap::slotCreatePendingFolders( int errorCode, const TQString& errorMsg )
02329 {
02330   Q_UNUSED( errorMsg );
02331   disconnect( account(), TQT_SIGNAL( connectionResult( int, const TQString& ) ),
02332               this, TQT_SLOT( slotCreatePendingFolders( int, const TQString& ) ) );
02333   if ( !errorCode ) {
02334     TQStringList::Iterator it = mFoldersPendingCreation.begin();
02335     for ( ; it != mFoldersPendingCreation.end(); ++it ) {
02336       createFolder( *it );
02337     }
02338   }
02339   mFoldersPendingCreation.clear();
02340 }
02341 
02342 //-----------------------------------------------------------------------------
02343 void KMFolderImap::search( const KMSearchPattern* pattern )
02344 {
02345   if ( !pattern || pattern->isEmpty() )
02346   {
02347     // not much to do here
02348     TQValueList<TQ_UINT32> serNums;
02349     emit searchResult( folder(), serNums, pattern, true );
02350     return;
02351   }
02352   SearchJob* job = new SearchJob( this, account(), pattern );
02353   connect( job, TQT_SIGNAL( searchDone( TQValueList<TQ_UINT32>, const KMSearchPattern*, bool ) ),
02354            this, TQT_SLOT( slotSearchDone( TQValueList<TQ_UINT32>, const KMSearchPattern*, bool ) ) );
02355   job->start();
02356 }
02357 
02358 //-----------------------------------------------------------------------------
02359 void KMFolderImap::slotSearchDone( TQValueList<TQ_UINT32> serNums,
02360                                    const KMSearchPattern* pattern,
02361                                    bool complete )
02362 {
02363   emit searchResult( folder(), serNums, pattern, complete );
02364 }
02365 
02366 //-----------------------------------------------------------------------------
02367 void KMFolderImap::search( const KMSearchPattern* pattern, TQ_UINT32 serNum )
02368 {
02369   if ( !pattern || pattern->isEmpty() )
02370   {
02371     // not much to do here
02372     emit searchDone( folder(), serNum, pattern, false );
02373     return;
02374   }
02375   SearchJob* job = new SearchJob( this, account(), pattern, serNum );
02376   connect( job, TQT_SIGNAL( searchDone( TQ_UINT32, const KMSearchPattern*, bool ) ),
02377            this, TQT_SLOT( slotSearchDone( TQ_UINT32, const KMSearchPattern*, bool ) ) );
02378   job->start();
02379 }
02380 
02381 //-----------------------------------------------------------------------------
02382 void KMFolderImap::slotSearchDone( TQ_UINT32 serNum, const KMSearchPattern* pattern,
02383                                    bool matches )
02384 {
02385   emit searchDone( folder(), serNum, pattern, matches );
02386 }
02387 
02388 //-----------------------------------------------------------------------------
02389 bool KMFolderImap::isMoveable() const
02390 {
02391   return ( hasChildren() == HasNoChildren &&
02392       !folder()->isSystemFolder() ) ? true : false;
02393 }
02394 
02395 //-----------------------------------------------------------------------------
02396 ulong KMFolderImap::serNumForUID( ulong uid )
02397 {
02398   if ( mUidMetaDataMap.find( uid ) ) {
02399     KMMsgMetaData *md = mUidMetaDataMap[uid];
02400     return md->serNum();
02401   } else {
02402     kdDebug(5006) << "serNumForUID: unknown uid " << uid << endl;
02403     return 0;
02404   }
02405 }
02406 
02407 //-----------------------------------------------------------------------------
02408 void KMFolderImap::saveMsgMetaData( KMMessage* msg, ulong uid )
02409 {
02410   if ( uid == 0 ) {
02411     uid = msg->UID();
02412   }
02413   ulong serNum = msg->getMsgSerNum();
02414   mUidMetaDataMap.replace( uid, new KMMsgMetaData(msg->status(), serNum) );
02415 }
02416 
02417 //-----------------------------------------------------------------------------
02418 void KMFolderImap::setImapPath( const TQString& path )
02419 {
02420   if ( path.isEmpty() ) {
02421     kdWarning(5006) << k_funcinfo << "ignoring empty path" << endl;
02422   } else {
02423     mImapPath = path;
02424   }
02425 }
02426 
02427 void KMFolderImap::finishMailCheck( const char *dbg, imapState state )
02428 {
02429   quiet( false );
02430   mContentState = state;
02431   emit folderComplete( this, mContentState == imapFinished );
02432   close(dbg);
02433 }
02434 
02435 bool KMFolderImap::canDeleteMessages() const
02436 {
02437   if ( isReadOnly() )
02438     return false;
02439   if ( mUserRightsState == KMail::ACLJobs::Ok && !(mUserRights & KMail::ACLJobs::Delete) )
02440     return false;
02441   return true;
02442 }
02443 
02444 #include "kmfolderimap.moc"