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