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; 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 f = static_cast<KMFolderImap*> 00671 (folder()->child()->createFolder(subfolderNames[i])->storage()); 00672 if (f) 00673 { 00674 f->close(); 00675 } else { 00676 kdWarning(5006) << "can't create folder " << subfolderNames[i] << endl; 00677 } 00678 } 00679 if (f) 00680 { 00681 // update progress 00682 account()->listDirProgressItem()->incCompletedItems(); 00683 account()->listDirProgressItem()->updateProgress(); 00684 account()->listDirProgressItem()->setStatus( folder()->prettyURL() + i18n(" completed") ); 00685 f->setAccount(mAccount); 00686 if ( f->hasChildren() == FolderStorage::ChildrenUnknown ) 00687 { 00688 // this is for new folders 00689 kmkernel->imapFolderMgr()->contentsChanged(); 00690 } 00691 00692 // update children state 00693 if ( subfolderAttributes[i].find( "haschildren", 0, false ) != -1 ) 00694 { 00695 f->setHasChildren( FolderStorage::HasChildren ); 00696 } else if ( subfolderAttributes[i].find( "hasnochildren", 0, false ) != -1 ) 00697 { 00698 f->setHasChildren( FolderStorage::HasNoChildren ); 00699 } else 00700 { 00701 if ( mAccount->listOnlyOpenFolders() ) 00702 f->setHasChildren( FolderStorage::ChildrenUnknown ); 00703 else // we don't need to be expandable 00704 f->setHasChildren( FolderStorage::HasNoChildren ); 00705 } 00706 f->setImapPath(subfolderPaths[i]); 00707 f->setNoContent(subfolderMimeTypes[i] == "inode/directory"); 00708 f->setNoChildren(subfolderMimeTypes[i] == "message/digest"); 00709 if ( mAccount->listOnlyOpenFolders() && 00710 f->hasChildren() != FolderStorage::ChildrenUnknown ) 00711 { 00712 // tell the tree our information changed 00713 kmkernel->imapFolderMgr()->contentsChanged(); 00714 } 00715 if ( ( subfolderMimeTypes[i] == "message/directory" || 00716 subfolderMimeTypes[i] == "inode/directory" ) && 00717 !mAccount->listOnlyOpenFolders() ) 00718 { 00719 f->listDirectory(); 00720 } 00721 } 00722 } // for subfolders 00723 } // inbox_only 00724 // now others should react on the changes 00725 kmkernel->imapFolderMgr()->quiet(false); 00726 emit directoryListingFinished( this ); 00727 account()->listDirProgressItem()->setComplete(); 00728 } 00729 00730 //----------------------------------------------------------------------------- 00731 void KMFolderImap::checkValidity() 00732 { 00733 if (!mAccount) { 00734 emit folderComplete(this, false); 00735 return; 00736 } 00737 KURL url = mAccount->getUrl(); 00738 url.setPath(imapPath() + ";UID=0:0"); 00739 kdDebug(5006) << "KMFolderImap::checkValidity of: " << imapPath() << endl; 00740 00741 if ( mAccount->makeConnection() == ImapAccountBase::Error ) { 00742 kdDebug(5006) << "KMFolderImap::checkValidity - got no connection" << endl; 00743 emit folderComplete(this, FALSE); 00744 mContentState = imapNoInformation; 00745 return; 00746 } else if ( mAccount->makeConnection() == ImapAccountBase::Connecting ) { 00747 // We'll wait for the connectionResult signal from the account. If it 00748 // errors, the above will catch it. 00749 kdDebug(5006) << "CheckValidity - waiting for connection" << endl; 00750 connect( mAccount, SIGNAL( connectionResult(int, const QString&) ), 00751 this, SLOT( checkValidity() ) ); 00752 return; 00753 } 00754 // Only check once at a time. 00755 if (mCheckingValidity) { 00756 kdDebug(5006) << "KMFolderImap::checkValidity - already checking" << endl; 00757 return; 00758 } 00759 // otherwise we already are inside a mailcheck 00760 if ( !mMailCheckProgressItem ) { 00761 mMailCheckProgressItem = ProgressManager::createProgressItem( 00762 account()->mailCheckProgressItem(), 00763 "MailCheck" + folder()->prettyURL(), 00764 folder()->prettyURL(), 00765 i18n("checking"), 00766 false, 00767 account()->useSSL() || account()->useTLS() ); 00768 } else { 00769 mMailCheckProgressItem->setProgress(0); 00770 } 00771 if ( account()->mailCheckProgressItem() ) { 00772 account()->mailCheckProgressItem()->setStatus( folder()->prettyURL() ); 00773 } 00774 ImapAccountBase::jobData jd( url.url() ); 00775 KIO::SimpleJob *job = KIO::get(url, FALSE, FALSE); 00776 KIO::Scheduler::assignJobToSlave(mAccount->slave(), job); 00777 mAccount->insertJob(job, jd); 00778 connect(job, SIGNAL(result(KIO::Job *)), 00779 SLOT(slotCheckValidityResult(KIO::Job *))); 00780 connect(job, SIGNAL(data(KIO::Job *, const QByteArray &)), 00781 SLOT(slotSimpleData(KIO::Job *, const QByteArray &))); 00782 // Only check once at a time. 00783 mCheckingValidity = true; 00784 } 00785 00786 00787 //----------------------------------------------------------------------------- 00788 ulong KMFolderImap::lastUid() 00789 { 00790 if (mLastUid) return mLastUid; 00791 open(); 00792 if (count() > 0) 00793 { 00794 KMMsgBase * base = getMsgBase(count()-1); 00795 mLastUid = base->UID(); 00796 } 00797 close(); 00798 return mLastUid; 00799 } 00800 00801 00802 //----------------------------------------------------------------------------- 00803 void KMFolderImap::slotCheckValidityResult(KIO::Job * job) 00804 { 00805 kdDebug(5006) << "KMFolderImap::slotCheckValidityResult of: " << fileName() << endl; 00806 mCheckingValidity = false; 00807 ImapAccountBase::JobIterator it = mAccount->findJob(job); 00808 if ( it == mAccount->jobsEnd() ) return; 00809 if (job->error()) { 00810 mAccount->handleJobError( job, i18n("Error while querying the server status.") ); 00811 mContentState = imapNoInformation; 00812 emit folderComplete(this, FALSE); 00813 } else { 00814 QCString cstr((*it).data.data(), (*it).data.size() + 1); 00815 int a = cstr.find("X-uidValidity: "); 00816 int b = cstr.find("\r\n", a); 00817 QString uidv; 00818 if ( (b - a - 15) >= 0 ) uidv = cstr.mid(a + 15, b - a - 15); 00819 a = cstr.find("X-Access: "); 00820 b = cstr.find("\r\n", a); 00821 QString access; 00822 if ( (b - a - 10) >= 0 ) access = cstr.mid(a + 10, b - a - 10); 00823 mReadOnly = access == "Read only"; 00824 int c = (*it).cdata.find("\r\nX-Count:"); 00825 int exists = -1; 00826 if ( c != -1 ) 00827 { 00828 bool ok; 00829 exists = (*it).cdata.mid( c+10, 00830 (*it).cdata.find("\r\n", c+1) - c-10 ).toInt(&ok); 00831 if ( !ok ) exists = -1; 00832 } 00833 QString startUid; 00834 if (uidValidity() != uidv) 00835 { 00836 // uidValidity changed 00837 kdDebug(5006) << "KMFolderImap::slotCheckValidityResult uidValidty changed." << endl; 00838 mAccount->ignoreJobsForFolder( folder() ); 00839 mLastUid = 0; 00840 uidmap.clear(); 00841 setUidValidity(uidv); 00842 } else { 00843 if (!mCheckFlags) 00844 startUid = QString::number(lastUid() + 1); 00845 } 00846 mAccount->removeJob(it); 00847 if ( mMailCheckProgressItem ) 00848 { 00849 if ( startUid.isEmpty() ) { 00850 // flags for all messages are loaded 00851 mMailCheckProgressItem->setTotalItems( exists ); 00852 } else { 00853 // only an approximation but doesn't hurt 00854 int remain = exists - count(); 00855 if ( remain < 0 ) remain = 1; 00856 mMailCheckProgressItem->setTotalItems( remain ); 00857 } 00858 mMailCheckProgressItem->setCompletedItems( 0 ); 00859 } 00860 reallyGetFolder(startUid); 00861 } 00862 } 00863 00864 //----------------------------------------------------------------------------- 00865 void KMFolderImap::getAndCheckFolder(bool force) 00866 { 00867 if (mNoContent) 00868 return getFolder(force); 00869 00870 if ( mAccount ) 00871 mAccount->processNewMailSingleFolder( folder() ); 00872 if (force) { 00873 // force an update 00874 mCheckFlags = TRUE; 00875 } 00876 } 00877 00878 //----------------------------------------------------------------------------- 00879 void KMFolderImap::getFolder(bool force) 00880 { 00881 mGuessedUnreadMsgs = -1; 00882 if (mNoContent) 00883 { 00884 mContentState = imapFinished; 00885 emit folderComplete(this, true); 00886 return; 00887 } 00888 mContentState = imapInProgress; 00889 if (force) { 00890 // force an update 00891 mCheckFlags = TRUE; 00892 } 00893 checkValidity(); 00894 } 00895 00896 00897 //----------------------------------------------------------------------------- 00898 void KMFolderImap::reallyGetFolder(const QString &startUid) 00899 { 00900 KURL url = mAccount->getUrl(); 00901 if ( mAccount->makeConnection() != ImapAccountBase::Connected ) 00902 { 00903 mContentState = imapNoInformation; 00904 emit folderComplete(this, FALSE); 00905 return; 00906 } 00907 quiet(true); 00908 if (startUid.isEmpty()) 00909 { 00910 if ( mMailCheckProgressItem ) 00911 mMailCheckProgressItem->setStatus( i18n("Retrieving message status") ); 00912 url.setPath(imapPath() + ";SECTION=UID FLAGS"); 00913 KIO::SimpleJob *job = KIO::listDir(url, FALSE); 00914 KIO::Scheduler::assignJobToSlave(mAccount->slave(), job); 00915 ImapAccountBase::jobData jd( url.url(), folder() ); 00916 jd.cancellable = true; 00917 mAccount->insertJob(job, jd); 00918 connect(job, SIGNAL(result(KIO::Job *)), 00919 this, SLOT(slotListFolderResult(KIO::Job *))); 00920 connect(job, SIGNAL(entries(KIO::Job *, const KIO::UDSEntryList &)), 00921 this, SLOT(slotListFolderEntries(KIO::Job *, 00922 const KIO::UDSEntryList &))); 00923 } else { 00924 if ( mMailCheckProgressItem ) 00925 mMailCheckProgressItem->setStatus( i18n("Retrieving messages") ); 00926 url.setPath(imapPath() + ";UID=" + startUid 00927 + ":*;SECTION=ENVELOPE"); 00928 KIO::SimpleJob *newJob = KIO::get(url, FALSE, FALSE); 00929 KIO::Scheduler::assignJobToSlave(mAccount->slave(), newJob); 00930 ImapAccountBase::jobData jd( url.url(), folder() ); 00931 jd.cancellable = true; 00932 mAccount->insertJob(newJob, jd); 00933 connect(newJob, SIGNAL(result(KIO::Job *)), 00934 this, SLOT(slotGetLastMessagesResult(KIO::Job *))); 00935 connect(newJob, SIGNAL(data(KIO::Job *, const QByteArray &)), 00936 this, SLOT(slotGetMessagesData(KIO::Job *, const QByteArray &))); 00937 } 00938 } 00939 00940 00941 //----------------------------------------------------------------------------- 00942 void KMFolderImap::slotListFolderResult(KIO::Job * job) 00943 { 00944 ImapAccountBase::JobIterator it = mAccount->findJob(job); 00945 if ( it == mAccount->jobsEnd() ) return; 00946 QString uids; 00947 if (job->error()) 00948 { 00949 mAccount->handleJobError( job, 00950 i18n("Error while listing the contents of the folder %1.").arg( label() ) ); 00951 quiet( false ); 00952 mContentState = imapNoInformation; 00953 emit folderComplete(this, FALSE); 00954 mAccount->removeJob(it); 00955 return; 00956 } 00957 mCheckFlags = FALSE; 00958 QStringList::Iterator uid; 00959 /* 00960 The code below does the following: 00961 - for each mail in the local store and each entry we got from the server, 00962 compare the local uid with the one from the server and update the status 00963 flags of the mails 00964 - for all mails that are not already locally present, start a job which 00965 gets the envelope of each 00966 - remove all locally present mails if the server does not list them anymore 00967 */ 00968 if ( count() ) { 00969 int idx = 0, c, serverFlags; 00970 ulong mailUid, serverUid; 00971 uid = (*it).items.begin(); 00972 while ( idx < count() && uid != (*it).items.end() ) { 00973 KMMsgBase *msgBase = getMsgBase( idx ); 00974 mailUid = msgBase->UID(); 00975 // parse the uid from the server and the flags out of the list from 00976 // the server. Format: 1234, 1 00977 c = (*uid).find(","); 00978 serverUid = (*uid).left( c ).toLong(); 00979 serverFlags = (*uid).mid( c+1 ).toInt(); 00980 if ( mailUid < serverUid ) { 00981 removeMsg( idx, TRUE ); 00982 } else if ( mailUid == serverUid ) { 00983 // if this is a read only folder, ignore status updates from the server 00984 // since we can't write our status back our local version is what has to 00985 // be considered correct. 00986 if (!mReadOnly) 00987 flagsToStatus( msgBase, serverFlags, false ); 00988 idx++; 00989 uid = (*it).items.remove(uid); 00990 } 00991 else break; // happens only, if deleted mails reappear on the server 00992 } 00993 // remove all remaining entries in the local cache, they are no longer 00994 // present on the server 00995 while (idx < count()) removeMsg(idx, TRUE); 00996 } 00997 // strip the flags from the list of uids, so it can be reused 00998 for (uid = (*it).items.begin(); uid != (*it).items.end(); uid++) 00999 (*uid).truncate((*uid).find(",")); 01000 ImapAccountBase::jobData jd( QString::null, (*it).parent ); 01001 jd.total = (*it).items.count(); 01002 if (jd.total == 0) 01003 { 01004 quiet(false); 01005 mContentState = imapFinished; 01006 emit folderComplete(this, TRUE); 01007 mAccount->removeJob(it); 01008 return; 01009 } 01010 if ( mMailCheckProgressItem ) 01011 { 01012 // next step for the progressitem 01013 mMailCheckProgressItem->setProgress( 0 ); 01014 mMailCheckProgressItem->setTotalItems( jd.total ); 01015 mMailCheckProgressItem->updateProgress(); 01016 mMailCheckProgressItem->setStatus( i18n("Retrieving messages") ); 01017 } 01018 01019 QStringList sets; 01020 uid = (*it).items.begin(); 01021 if (jd.total == 1) sets.append(*uid + ":" + *uid); 01022 else sets = makeSets( (*it).items ); 01023 mAccount->removeJob(it); // don't use *it below 01024 01025 // Now kick off the getting of envelopes for the new mails in the folder 01026 for (QStringList::Iterator i = sets.begin(); i != sets.end(); ++i) 01027 { 01028 KURL url = mAccount->getUrl(); 01029 url.setPath(imapPath() + ";UID=" + *i + ";SECTION=ENVELOPE"); 01030 if ( mAccount->makeConnection() != ImapAccountBase::Connected ) 01031 { 01032 quiet(false); 01033 emit folderComplete(this, FALSE); 01034 return; 01035 } 01036 KIO::SimpleJob *newJob = KIO::get(url, FALSE, FALSE); 01037 jd.url = url.url(); 01038 KIO::Scheduler::assignJobToSlave(mAccount->slave(), newJob); 01039 mAccount->insertJob(newJob, jd); 01040 connect(newJob, SIGNAL(result(KIO::Job *)), 01041 this, (i == sets.at(sets.count() - 1)) 01042 ? SLOT(slotGetLastMessagesResult(KIO::Job *)) 01043 : SLOT(slotGetMessagesResult(KIO::Job *))); 01044 connect(newJob, SIGNAL(data(KIO::Job *, const QByteArray &)), 01045 this, SLOT(slotGetMessagesData(KIO::Job *, const QByteArray &))); 01046 } 01047 } 01048 01049 01050 //----------------------------------------------------------------------------- 01051 void KMFolderImap::slotListFolderEntries(KIO::Job * job, 01052 const KIO::UDSEntryList & uds) 01053 { 01054 ImapAccountBase::JobIterator it = mAccount->findJob(job); 01055 if ( it == mAccount->jobsEnd() ) return; 01056 QString mimeType, name; 01057 long int flags = 0; 01058 for (KIO::UDSEntryList::ConstIterator udsIt = uds.begin(); 01059 udsIt != uds.end(); udsIt++) 01060 { 01061 for (KIO::UDSEntry::ConstIterator eIt = (*udsIt).begin(); 01062 eIt != (*udsIt).end(); eIt++) 01063 { 01064 if ((*eIt).m_uds == KIO::UDS_NAME) 01065 name = (*eIt).m_str; 01066 else if ((*eIt).m_uds == KIO::UDS_MIME_TYPE) 01067 mimeType = (*eIt).m_str; 01068 else if ((*eIt).m_uds == KIO::UDS_ACCESS) 01069 flags = (*eIt).m_long; 01070 } 01071 if ((mimeType == "message/rfc822-imap" || mimeType == "message/rfc822") && 01072 !(flags & 8)) { 01073 (*it).items.append(name + "," + QString::number(flags)); 01074 if ( mMailCheckProgressItem ) { 01075 mMailCheckProgressItem->incCompletedItems(); 01076 mMailCheckProgressItem->updateProgress(); 01077 } 01078 } 01079 } 01080 } 01081 01082 01083 //----------------------------------------------------------------------------- 01084 void KMFolderImap::flagsToStatus(KMMsgBase *msg, int flags, bool newMsg) 01085 { 01086 if (flags & 4) 01087 msg->setStatus( KMMsgStatusFlag ); 01088 if (flags & 2) 01089 msg->setStatus( KMMsgStatusReplied ); 01090 if (flags & 1) 01091 msg->setStatus( KMMsgStatusOld ); 01092 01093 // In case the message does not have the seen flag set, override our local 01094 // notion that it is read. Otherwise the count of unread messages and the 01095 // number of messages which actually show up as read can go out of sync. 01096 if (msg->isOfUnknownStatus() || !(flags&1) ) { 01097 if (newMsg) 01098 msg->setStatus( KMMsgStatusNew ); 01099 else 01100 msg->setStatus( KMMsgStatusUnread ); 01101 } 01102 } 01103 01104 01105 //----------------------------------------------------------------------------- 01106 QString KMFolderImap::statusToFlags(KMMsgStatus status) 01107 { 01108 QString flags; 01109 if (status & KMMsgStatusDeleted) 01110 flags = "\\DELETED"; 01111 else { 01112 if (status & KMMsgStatusOld || status & KMMsgStatusRead) 01113 flags = "\\SEEN "; 01114 if (status & KMMsgStatusReplied) 01115 flags += "\\ANSWERED "; 01116 if (status & KMMsgStatusFlag) 01117 flags += "\\FLAGGED"; 01118 } 01119 01120 return flags.simplifyWhiteSpace(); 01121 } 01122 01123 //------------------------------------------------------------- 01124 void 01125 KMFolderImap::ignoreJobsForMessage( KMMessage* msg ) 01126 { 01127 if ( !msg || msg->transferInProgress() || 01128 !msg->parent() || msg->parent()->folderType() != KMFolderTypeImap ) 01129 return; 01130 KMAcctImap *account; 01131 if ( !(account = static_cast<KMFolderImap*>(msg->storage())->account()) ) 01132 return; 01133 01134 account->ignoreJobsForMessage( msg ); 01135 } 01136 01137 //----------------------------------------------------------------------------- 01138 void KMFolderImap::slotGetMessagesData(KIO::Job * job, const QByteArray & data) 01139 { 01140 if ( data.isEmpty() ) return; // optimization 01141 ImapAccountBase::JobIterator it = mAccount->findJob(job); 01142 if ( it == mAccount->jobsEnd() ) return; 01143 (*it).cdata += QCString(data, data.size() + 1); 01144 int pos = (*it).cdata.find("\r\n--IMAPDIGEST"); 01145 if (pos > 0) 01146 { 01147 int p = (*it).cdata.find("\r\nX-uidValidity:"); 01148 if (p != -1) setUidValidity((*it).cdata 01149 .mid(p + 17, (*it).cdata.find("\r\n", p+1) - p - 17)); 01150 int c = (*it).cdata.find("\r\nX-Count:"); 01151 if ( c != -1 ) 01152 { 01153 bool ok; 01154 int exists = (*it).cdata.mid( c+10, 01155 (*it).cdata.find("\r\n", c+1) - c-10 ).toInt(&ok); 01156 if ( ok && exists < count() ) { 01157 kdDebug(5006) << "KMFolderImap::slotGetMessagesData - server has less messages (" << 01158 exists << ") then folder (" << count() << "), so reload" << endl; 01159 reallyGetFolder( QString::null ); 01160 (*it).cdata.remove(0, pos); 01161 return; 01162 } else if ( ok ) { 01163 int delta = exists - count(); 01164 if ( mMailCheckProgressItem ) { 01165 mMailCheckProgressItem->setTotalItems( delta ); 01166 mMailCheckProgressItem->setStatus( i18n("Retrieving message list") ); 01167 } 01168 } 01169 } 01170 (*it).cdata.remove(0, pos); 01171 } 01172 pos = (*it).cdata.find("\r\n--IMAPDIGEST", 1); 01173 int flags; 01174 open(); 01175 while (pos >= 0) 01176 { 01177 KMMessage *msg = new KMMessage; 01178 msg->setComplete(false); 01179 msg->setReadyToShow(false); 01180 msg->fromString((*it).cdata.mid(16, pos - 16)); 01181 flags = msg->headerField("X-Flags").toInt(); 01182 ulong uid = msg->UID(); 01183 bool ok = true; 01184 if ( uid <= lastUid() ) 01185 { 01186 // as some servers send the messages out of order 01187 // we have to check if the message really already exists 01188 int idx = 0; 01189 KMMsgBase *msg; 01190 while ( idx < count() ) 01191 { 01192 msg = getMsgBase( idx ); 01193 if ( msg && msg->UID() == uid ) 01194 { 01195 ok = false; // exists, no need to create it 01196 break; 01197 } 01198 ++idx; 01199 } 01200 } 01201 // deleted flag 01202 if ( flags & 8 ) 01203 ok = false; 01204 if ( !ok ) { 01205 delete msg; 01206 msg = 0; 01207 } else { 01208 if (uidmap.find(uid)) { 01209 // assign the sernum from the cache 01210 const ulong sernum = (ulong) uidmap[uid]; 01211 msg->setMsgSerNum(sernum); 01212 // delete the entry 01213 uidmap.remove(uid); 01214 } 01215 KMFolderMbox::addMsg(msg, 0); 01216 // Transfer the status, if it is cached. 01217 QString id = msg->msgIdMD5(); 01218 if ( mMetaDataMap.find( id ) ) { 01219 KMMsgMetaData *md = mMetaDataMap[id]; 01220 msg->setStatus( md->status() ); 01221 if ( md->serNum() != 0 ) 01222 msg->setMsgSerNum( md->serNum() ); 01223 mMetaDataMap.remove( id ); 01224 delete md; 01225 } 01226 // Merge with the flags from the server. 01227 flagsToStatus((KMMsgBase*)msg, flags); 01228 // set the correct size 01229 msg->setMsgSizeServer( msg->headerField("X-Length").toUInt() ); 01230 msg->setUID(uid); 01231 01232 if (count() > 1) unGetMsg(count() - 1); 01233 mLastUid = uid; 01234 if ( mMailCheckProgressItem ) { 01235 mMailCheckProgressItem->incCompletedItems(); 01236 mMailCheckProgressItem->updateProgress(); 01237 } 01238 } 01239 (*it).cdata.remove(0, pos); 01240 (*it).done++; 01241 pos = (*it).cdata.find("\r\n--IMAPDIGEST", 1); 01242 } // while 01243 close(); 01244 } 01245 01246 //------------------------------------------------------------- 01247 FolderJob* 01248 KMFolderImap::doCreateJob( KMMessage *msg, FolderJob::JobType jt, 01249 KMFolder *folder, QString partSpecifier, 01250 const AttachmentStrategy *as ) const 01251 { 01252 KMFolderImap* kmfi = folder? dynamic_cast<KMFolderImap*>(folder->storage()) : 0; 01253 if ( jt == FolderJob::tGetMessage && partSpecifier == "STRUCTURE" && 01254 mAccount && mAccount->loadOnDemand() && 01255 ( msg->msgSizeServer() > 5000 || msg->msgSizeServer() == 0 ) && 01256 ( msg->signatureState() == KMMsgNotSigned || 01257 msg->signatureState() == KMMsgSignatureStateUnknown ) && 01258 ( msg->encryptionState() == KMMsgNotEncrypted || 01259 msg->encryptionState() == KMMsgEncryptionStateUnknown ) ) 01260 { 01261 // load-on-demand: retrieve the BODYSTRUCTURE and to speed things up also the headers 01262 // this is not activated for small or signed messages 01263 ImapJob *job = new ImapJob( msg, jt, kmfi, "HEADER" ); 01264 job->start(); 01265 ImapJob *job2 = new ImapJob( msg, jt, kmfi, "STRUCTURE", as ); 01266 job2->start(); 01267 job->setParentFolder( this ); 01268 return job; 01269 } else { 01270 // download complete message or part (attachment) 01271 if ( partSpecifier == "STRUCTURE" ) // hide from outside 01272 partSpecifier = QString::null; 01273 01274 ImapJob *job = new ImapJob( msg, jt, kmfi, partSpecifier ); 01275 job->setParentFolder( this ); 01276 return job; 01277 } 01278 } 01279 01280 //------------------------------------------------------------- 01281 FolderJob* 01282 KMFolderImap::doCreateJob( QPtrList<KMMessage>& msgList, const QString& sets, 01283 FolderJob::JobType jt, KMFolder *folder ) const 01284 { 01285 KMFolderImap* kmfi = dynamic_cast<KMFolderImap*>(folder->storage()); 01286 ImapJob *job = new ImapJob( msgList, sets, jt, kmfi ); 01287 job->setParentFolder( this ); 01288 return job; 01289 } 01290 01291 //----------------------------------------------------------------------------- 01292 void KMFolderImap::getMessagesResult(KIO::Job * job, bool lastSet) 01293 { 01294 ImapAccountBase::JobIterator it = mAccount->findJob(job); 01295 if ( it == mAccount->jobsEnd() ) return; 01296 if (job->error()) 01297 { 01298 mAccount->handleJobError( job, i18n("Error while retrieving messages.") ); 01299 mContentState = imapNoInformation; 01300 quiet( false ); 01301 emit folderComplete(this, false); 01302 } 01303 else 01304 { 01305 if (lastSet) 01306 { 01307 mContentState = imapFinished; 01308 quiet(false); 01309 emit folderComplete(this, true); 01310 } 01311 mAccount->removeJob(it); 01312 } 01313 } 01314 01315 01316 //----------------------------------------------------------------------------- 01317 void KMFolderImap::slotGetLastMessagesResult(KIO::Job * job) 01318 { 01319 getMessagesResult(job, true); 01320 } 01321 01322 01323 //----------------------------------------------------------------------------- 01324 void KMFolderImap::slotGetMessagesResult(KIO::Job * job) 01325 { 01326 getMessagesResult(job, false); 01327 } 01328 01329 01330 //----------------------------------------------------------------------------- 01331 void KMFolderImap::createFolder(const QString &name) 01332 { 01333 if ( mAccount->makeConnection() == ImapAccountBase::Error ) { 01334 kdWarning(5006) << "KMFolderImap::createFolder - got no connection" << endl; 01335 return; 01336 } else if ( mAccount->makeConnection() == ImapAccountBase::Connecting ) { 01337 // We'll wait for the connectionResult signal from the account. 01338 kdDebug(5006) << "KMFolderImap::createFolder - waiting for connection" << endl; 01339 01340 if ( mFoldersPendingCreation.isEmpty() ) { 01341 // first folder, connect 01342 connect( mAccount, SIGNAL( connectionResult(int, const QString&) ), 01343 this, SLOT( slotCreatePendingFolders() ) ); 01344 } 01345 mFoldersPendingCreation << name; 01346 return; 01347 } 01348 KURL url = mAccount->getUrl(); 01349 url.setPath(imapPath() + name); 01350 01351 KIO::SimpleJob *job = KIO::mkdir(url); 01352 KIO::Scheduler::assignJobToSlave(mAccount->slave(), job); 01353 ImapAccountBase::jobData jd( url.url(), folder() ); 01354 jd.items = name; 01355 mAccount->insertJob(job, jd); 01356 connect(job, SIGNAL(result(KIO::Job *)), 01357 this, SLOT(slotCreateFolderResult(KIO::Job *))); 01358 } 01359 01360 01361 //----------------------------------------------------------------------------- 01362 void KMFolderImap::slotCreateFolderResult(KIO::Job * job) 01363 { 01364 ImapAccountBase::JobIterator it = mAccount->findJob(job); 01365 if ( it == mAccount->jobsEnd() ) return; 01366 if (job->error()) 01367 { 01368 if ( job->error() == KIO::ERR_COULD_NOT_MKDIR ) { 01369 // Creating a folder failed, remove it from the tree. 01370 mAccount->listDirectory( ); 01371 } 01372 mAccount->handleJobError( job, i18n("Error while creating a folder.") ); 01373 } else { 01374 listDirectory(); 01375 mAccount->removeJob(job); 01376 } 01377 } 01378 01379 01380 //----------------------------------------------------------------------------- 01381 static QTextCodec *sUtf7Codec = 0; 01382 01383 QTextCodec * KMFolderImap::utf7Codec() 01384 { 01385 if (!sUtf7Codec) sUtf7Codec = QTextCodec::codecForName("utf-7"); 01386 return sUtf7Codec; 01387 } 01388 01389 01390 //----------------------------------------------------------------------------- 01391 QString KMFolderImap::encodeFileName(const QString &name) 01392 { 01393 QString result = utf7Codec()->fromUnicode(name); 01394 return KURL::encode_string_no_slash(result); 01395 } 01396 01397 01398 //----------------------------------------------------------------------------- 01399 QString KMFolderImap::decodeFileName(const QString &name) 01400 { 01401 QString result = KURL::decode_string(name); 01402 return utf7Codec()->toUnicode(result.latin1()); 01403 } 01404 01405 //----------------------------------------------------------------------------- 01406 bool KMFolderImap::autoExpunge() 01407 { 01408 if (mAccount) 01409 return mAccount->autoExpunge(); 01410 01411 return false; 01412 } 01413 01414 01415 //----------------------------------------------------------------------------- 01416 void KMFolderImap::slotSimpleData(KIO::Job * job, const QByteArray & data) 01417 { 01418 if ( data.isEmpty() ) return; // optimization 01419 ImapAccountBase::JobIterator it = mAccount->findJob(job); 01420 if ( it == mAccount->jobsEnd() ) return; 01421 QBuffer buff((*it).data); 01422 buff.open(IO_WriteOnly | IO_Append); 01423 buff.writeBlock(data.data(), data.size()); 01424 buff.close(); 01425 } 01426 01427 //----------------------------------------------------------------------------- 01428 void KMFolderImap::deleteMessage(KMMessage * msg) 01429 { 01430 KURL url = mAccount->getUrl(); 01431 KMFolderImap *msg_parent = static_cast<KMFolderImap*>(msg->storage()); 01432 ulong uid = msg->UID(); 01433 /* If the uid is empty the delete job below will nuke all mail in the 01434 folder, so we better safeguard against that. See ::expungeFolder, as 01435 to why. :( */ 01436 if ( uid == 0 ) { 01437 kdDebug( 5006 ) << "KMFolderImap::deleteMessage: Attempt to delete " 01438 "an empty UID. Aborting." << endl; 01439 return; 01440 } 01441 url.setPath(msg_parent->imapPath() + ";UID=" + QString::number(uid) ); 01442 if ( mAccount->makeConnection() != ImapAccountBase::Connected ) 01443 return; 01444 KIO::SimpleJob *job = KIO::file_delete(url, FALSE); 01445 KIO::Scheduler::assignJobToSlave(mAccount->slave(), job); 01446 ImapAccountBase::jobData jd( url.url(), 0 ); 01447 mAccount->insertJob(job, jd); 01448 connect(job, SIGNAL(result(KIO::Job *)), 01449 mAccount, SLOT(slotSimpleResult(KIO::Job *))); 01450 } 01451 01452 void KMFolderImap::deleteMessage(const QPtrList<KMMessage>& msgList) 01453 { 01454 QValueList<ulong> uids; 01455 getUids(msgList, uids); 01456 QStringList sets = makeSets(uids); 01457 01458 KURL url = mAccount->getUrl(); 01459 KMFolderImap *msg_parent = static_cast<KMFolderImap*>(msgList.getFirst()->storage()); 01460 for ( QStringList::Iterator it = sets.begin(); it != sets.end(); ++it ) 01461 { 01462 QString uid = *it; 01463 // Don't delete with no uid, that nukes the folder. Should not happen, but 01464 // better safe than sorry. 01465 if ( uid.isEmpty() ) continue; 01466 url.setPath(msg_parent->imapPath() + ";UID=" + uid); 01467 if ( mAccount->makeConnection() != ImapAccountBase::Connected ) 01468 return; 01469 KIO::SimpleJob *job = KIO::file_delete(url, FALSE); 01470 KIO::Scheduler::assignJobToSlave(mAccount->slave(), job); 01471 ImapAccountBase::jobData jd( url.url(), 0 ); 01472 mAccount->insertJob(job, jd); 01473 connect(job, SIGNAL(result(KIO::Job *)), 01474 mAccount, SLOT(slotSimpleResult(KIO::Job *))); 01475 } 01476 } 01477 01478 //----------------------------------------------------------------------------- 01479 void KMFolderImap::setStatus(int idx, KMMsgStatus status, bool toggle) 01480 { 01481 QValueList<int> ids; ids.append(idx); 01482 setStatus(ids, status, toggle); 01483 } 01484 01485 void KMFolderImap::setStatus(QValueList<int>& ids, KMMsgStatus status, bool toggle) 01486 { 01487 FolderStorage::setStatus(ids, status, toggle); 01488 if (mReadOnly) return; 01489 01490 /* The status has been already set in the local index. Update the flags on 01491 * the server. To avoid doing that for each message individually, group them 01492 * by the status string they will be assigned and make sets for each of those 01493 * groups of mails. This is necessary because the imap kio_slave status job 01494 * does not append flags but overwrites them. Example: 01495 * 01496 * 2 important mails and 3 unimportant mail, all unread. Mark all as read calls 01497 * this method with a list of uids. The 2 important mails need to get the string 01498 * \SEEN \FLAGGED while the others need to get just \SEEN. Build sets for each 01499 * of those and sort them, so the server can handle them efficiently. */ 01500 QMap< QString, QStringList > groups; 01501 for ( QValueList<int>::Iterator it = ids.begin(); it != ids.end(); ++it ) { 01502 KMMessage *msg = 0; 01503 bool unget = !isMessage(*it); 01504 msg = getMsg(*it); 01505 if (!msg) continue; 01506 QString flags = statusToFlags(msg->status()); 01507 // Collect uids for each type of flags. 01508 groups[flags].append(QString::number(msg->UID())); 01509 if (unget) unGetMsg(*it); 01510 } 01511 QMapIterator< QString, QStringList > dit; 01512 for ( dit = groups.begin(); dit != groups.end(); ++dit ) { 01513 QCString flags = dit.key().latin1(); 01514 QStringList sets = makeSets( (*dit), true ); 01515 // Send off a status setting job for each set. 01516 for ( QStringList::Iterator slit = sets.begin(); slit != sets.end(); ++slit ) { 01517 QString imappath = imapPath() + ";UID=" + ( *slit ); 01518 mAccount->setImapStatus(folder(), imappath, flags); 01519 } 01520 } 01521 if ( mContentState == imapInProgress ) { 01522 // we're currently get'ing this folder 01523 // to make sure that we get the latest flags abort the current listing and 01524 // create a new one 01525 disconnect(this, SLOT(slotListFolderResult(KIO::Job *))); 01526 reallyGetFolder( QString::null ); 01527 } 01528 } 01529 01530 //----------------------------------------------------------------------------- 01531 QStringList KMFolderImap::makeSets(const QStringList& uids, bool sort) 01532 { 01533 QValueList<ulong> tmp; 01534 for ( QStringList::ConstIterator it = uids.begin(); it != uids.end(); ++it ) 01535 tmp.append( (*it).toInt() ); 01536 return makeSets(tmp, sort); 01537 } 01538 01539 QStringList KMFolderImap::makeSets( QValueList<ulong>& uids, bool sort ) 01540 { 01541 QStringList sets; 01542 QString set; 01543 01544 if (uids.size() == 1) 01545 { 01546 sets.append(QString::number(uids.first())); 01547 return sets; 01548 } 01549 01550 if (sort) qHeapSort(uids); 01551 01552 ulong last = 0; 01553 // needed to make a uid like 124 instead of 124:124 01554 bool inserted = false; 01555 /* iterate over uids and build sets like 120:122,124,126:150 */ 01556 for ( QValueList<ulong>::Iterator it = uids.begin(); it != uids.end(); ++it ) 01557 { 01558 if (it == uids.begin() || set.isEmpty()) { 01559 set = QString::number(*it); 01560 inserted = true; 01561 } else 01562 { 01563 if (last+1 != *it) 01564 { 01565 // end this range 01566 if (inserted) 01567 set += ',' + QString::number(*it); 01568 else 01569 set += ':' + QString::number(last) + ',' + QString::number(*it); 01570 inserted = true; 01571 if (set.length() > 100) 01572 { 01573 // just in case the server has a problem with longer lines.. 01574 sets.append(set); 01575 set = ""; 01576 } 01577 } else { 01578 inserted = false; 01579 } 01580 } 01581 last = *it; 01582 } 01583 // last element 01584 if (!inserted) 01585 set += ':' + QString::number(uids.last()); 01586 01587 if (!set.isEmpty()) sets.append(set); 01588 01589 return sets; 01590 } 01591 01592 //----------------------------------------------------------------------------- 01593 void KMFolderImap::getUids(QValueList<int>& ids, QValueList<ulong>& uids) 01594 { 01595 KMMsgBase *msg = 0; 01596 // get the uids 01597 for ( QValueList<int>::Iterator it = ids.begin(); it != ids.end(); ++it ) 01598 { 01599 msg = getMsgBase(*it); 01600 if (!msg) continue; 01601 uids.append(msg->UID()); 01602 } 01603 } 01604 01605 void KMFolderImap::getUids(const QPtrList<KMMessage>& msgList, QValueList<ulong>& uids, KMFolder* msgParent) 01606 { 01607 KMMessage *msg = 0; 01608 01609 if (!msgParent) 01610 msgParent = msgList.getFirst()->parent(); 01611 if (!msgParent) return; 01612 01613 QPtrListIterator<KMMessage> it( msgList ); 01614 while ( (msg = it.current()) != 0 ) { 01615 ++it; 01616 uids.append(msg->UID()); 01617 } 01618 } 01619 01620 //----------------------------------------------------------------------------- 01621 void KMFolderImap::expungeFolder(KMFolderImap * aFolder, bool quiet) 01622 { 01623 aFolder->setNeedsCompacting(FALSE); 01624 KURL url = mAccount->getUrl(); 01625 url.setPath(aFolder->imapPath() + ";UID=*"); 01626 if ( mAccount->makeConnection() != ImapAccountBase::Connected ) 01627 return; 01628 KIO::SimpleJob *job = KIO::file_delete(url, FALSE); 01629 KIO::Scheduler::assignJobToSlave(mAccount->slave(), job); 01630 ImapAccountBase::jobData jd( url.url(), 0 ); 01631 jd.quiet = quiet; 01632 mAccount->insertJob(job, jd); 01633 connect(job, SIGNAL(result(KIO::Job *)), 01634 mAccount, SLOT(slotSimpleResult(KIO::Job *))); 01635 } 01636 01637 //----------------------------------------------------------------------------- 01638 void KMFolderImap::slotProcessNewMail( int errorCode, const QString &errorMsg ) 01639 { 01640 Q_UNUSED( errorMsg ); 01641 disconnect( mAccount, SIGNAL( connectionResult(int, const QString&) ), 01642 this, SLOT( slotProcessNewMail(int, const QString&) ) ); 01643 if ( !errorCode ) 01644 processNewMail( false ); 01645 else 01646 emit numUnreadMsgsChanged( folder() ); 01647 } 01648 01649 //----------------------------------------------------------------------------- 01650 bool KMFolderImap::processNewMail(bool) 01651 { 01652 // a little safety 01653 if ( !mAccount ) { 01654 kdDebug(5006) << "KMFolderImap::processNewMail - account is null!" << endl; 01655 return false; 01656 } 01657 if (imapPath().isEmpty()) { 01658 kdDebug(5006) << "KMFolderImap::processNewMail - imapPath of " << name() << " is empty!" << endl; 01659 kmkernel->imapFolderMgr()->remove( folder() ); 01660 return false; 01661 } 01662 // check the connection 01663 if ( mAccount->makeConnection() == ImapAccountBase::Error ) { 01664 kdDebug(5006) << "KMFolderImap::processNewMail - got no connection!" << endl; 01665 return false; 01666 } else if ( mAccount->makeConnection() == ImapAccountBase::Connecting ) 01667 { 01668 // wait 01669 kdDebug(5006) << "KMFolderImap::processNewMail - waiting for connection" << endl; 01670 connect( mAccount, SIGNAL( connectionResult(int, const QString&) ), 01671 this, SLOT( slotProcessNewMail(int, const QString&) ) ); 01672 return true; 01673 } 01674 KURL url = mAccount->getUrl(); 01675 if (mReadOnly) 01676 url.setPath(imapPath() + ";SECTION=UIDNEXT"); 01677 else 01678 url.setPath(imapPath() + ";SECTION=UNSEEN"); 01679 01680 mMailCheckProgressItem = ProgressManager::createProgressItem( 01681 "MailCheckAccount" + account()->name(), 01682 "MailCheck" + folder()->prettyURL(), 01683 folder()->prettyURL(), 01684 i18n("updating message counts"), 01685 false, 01686 account()->useSSL() || account()->useTLS() ); 01687 01688 KIO::SimpleJob *job = KIO::stat(url, FALSE); 01689 KIO::Scheduler::assignJobToSlave(mAccount->slave(), job); 01690 ImapAccountBase::jobData jd(url.url(), folder() ); 01691 jd.cancellable = true; 01692 mAccount->insertJob(job, jd); 01693 connect(job, SIGNAL(result(KIO::Job *)), 01694 SLOT(slotStatResult(KIO::Job *))); 01695 return true; 01696 } 01697 01698 01699 //----------------------------------------------------------------------------- 01700 void KMFolderImap::slotStatResult(KIO::Job * job) 01701 { 01702 ImapAccountBase::JobIterator it = mAccount->findJob(job); 01703 if ( it == mAccount->jobsEnd() ) return; 01704 mAccount->removeJob(it); 01705 slotCompleteMailCheckProgress(); 01706 if (job->error()) 01707 { 01708 mAccount->handleJobError( job, i18n("Error while getting folder information.") ); 01709 } else { 01710 KIO::UDSEntry uds = static_cast<KIO::StatJob*>(job)->statResult(); 01711 for (KIO::UDSEntry::ConstIterator it = uds.begin(); it != uds.end(); it++) 01712 { 01713 if ((*it).m_uds == KIO::UDS_SIZE) 01714 { 01715 if (mReadOnly) 01716 { 01717 mGuessedUnreadMsgs = -1; 01718 mGuessedUnreadMsgs = countUnread() + (*it).m_long - lastUid() - 1; 01719 if (mGuessedUnreadMsgs < 0) mGuessedUnreadMsgs = 0; 01720 } else { 01721 mGuessedUnreadMsgs = (*it).m_long; 01722 } 01723 } 01724 } 01725 emit numUnreadMsgsChanged( folder() ); 01726 } 01727 } 01728 01729 //----------------------------------------------------------------------------- 01730 int KMFolderImap::create(bool imap) 01731 { 01732 readConfig(); 01733 mUnreadMsgs = -1; 01734 return KMFolderMbox::create(imap); 01735 } 01736 01737 QValueList<ulong> KMFolderImap::splitSets(const QString uids) 01738 { 01739 QValueList<ulong> uidlist; 01740 01741 // ex: 1205,1204,1203,1202,1236:1238 01742 QString buffer = QString::null; 01743 int setstart = -1; 01744 // iterate over the uids 01745 for (uint i = 0; i < uids.length(); i++) 01746 { 01747 QChar chr = uids[i]; 01748 if (chr == ',') 01749 { 01750 if (setstart > -1) 01751 { 01752 // a range (uid:uid) was before 01753 for (int j = setstart; j <= buffer.toInt(); j++) 01754 { 01755 uidlist.append(j); 01756 } 01757 setstart = -1; 01758 } else { 01759 // single uid 01760 uidlist.append(buffer.toInt()); 01761 } 01762 buffer = ""; 01763 } else if (chr == ':') { 01764 // remember the start of the range 01765 setstart = buffer.toInt(); 01766 buffer = ""; 01767 } else if (chr.category() == QChar::Number_DecimalDigit) { 01768 // digit 01769 buffer += chr; 01770 } else { 01771 // ignore 01772 } 01773 } 01774 // process the last data 01775 if (setstart > -1) 01776 { 01777 for (int j = setstart; j <= buffer.toInt(); j++) 01778 { 01779 uidlist.append(j); 01780 } 01781 } else { 01782 uidlist.append(buffer.toInt()); 01783 } 01784 01785 return uidlist; 01786 } 01787 01788 //----------------------------------------------------------------------------- 01789 int KMFolderImap::expungeContents() 01790 { 01791 int rc = KMFolderMbox::expungeContents(); 01792 if (autoExpunge()) 01793 expungeFolder(this, true); 01794 getFolder(); 01795 01796 return rc; 01797 } 01798 01799 //----------------------------------------------------------------------------- 01800 void 01801 KMFolderImap::setUserRights( unsigned int userRights ) 01802 { 01803 mUserRights = userRights; 01804 kdDebug(5006) << imapPath() << " setUserRights: " << userRights << endl; 01805 } 01806 01807 //----------------------------------------------------------------------------- 01808 void KMFolderImap::slotCompleteMailCheckProgress() 01809 { 01810 if ( mMailCheckProgressItem ) { 01811 mMailCheckProgressItem->setComplete(); 01812 } 01813 } 01814 01815 //----------------------------------------------------------------------------- 01816 void KMFolderImap::setSubfolderState( imapState state ) 01817 { 01818 mSubfolderState = state; 01819 if ( state == imapNoInformation && folder()->child() ) 01820 { 01821 // pass through to childs 01822 KMFolderNode* node; 01823 QPtrListIterator<KMFolderNode> it( *folder()->child() ); 01824 for ( ; (node = it.current()); ) 01825 { 01826 ++it; 01827 if (node->isDir()) continue; 01828 KMFolder *folder = static_cast<KMFolder*>(node); 01829 static_cast<KMFolderImap*>(folder->storage())->setSubfolderState( state ); 01830 } 01831 } 01832 } 01833 01834 //----------------------------------------------------------------------------- 01835 void KMFolderImap::setIncludeInMailCheck( bool check ) 01836 { 01837 bool changed = ( mCheckMail != check ); 01838 mCheckMail = check; 01839 if ( changed ) 01840 account()->slotUpdateFolderList(); 01841 } 01842 01843 //----------------------------------------------------------------------------- 01844 void KMFolderImap::setAlreadyRemoved( bool removed ) 01845 { 01846 mAlreadyRemoved = removed; 01847 if ( folder()->child() ) 01848 { 01849 // pass through to childs 01850 KMFolderNode* node; 01851 QPtrListIterator<KMFolderNode> it( *folder()->child() ); 01852 for ( ; (node = it.current()); ) 01853 { 01854 ++it; 01855 if (node->isDir()) continue; 01856 KMFolder *folder = static_cast<KMFolder*>(node); 01857 static_cast<KMFolderImap*>(folder->storage())->setAlreadyRemoved( removed ); 01858 } 01859 } 01860 } 01861 01862 void KMFolderImap::slotCreatePendingFolders() 01863 { 01864 QStringList::Iterator it = mFoldersPendingCreation.begin(); 01865 for ( ; it != mFoldersPendingCreation.end(); ++it ) { 01866 createFolder( *it ); 01867 } 01868 mFoldersPendingCreation.clear(); 01869 } 01870 01871 #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 Fri Aug 27 12:52:34 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003