kmail Library API Documentation

kmfolderimap.cpp

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