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 <kio/scheduler.h>
00056 #include <kconfig.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
00094
00095
00096
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
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 )
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 KConfig* config = KMKernel::config();
00190 KConfigGroupSaver 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 );
00206
00207 KMFolderMbox::readConfig();
00208 }
00209
00210
00211 void KMFolderImap::writeConfig()
00212 {
00213 KConfig* config = KMKernel::config();
00214 KConfigGroupSaver 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
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 KIO::SimpleJob *job = KIO::file_delete(url, false);
00243 KIO::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(KIO::Job *)),
00253 this, TQT_SLOT(slotRemoveFolderResult(KIO::Job *)));
00254 }
00255
00256
00257 void KMFolderImap::slotRemoveFolderResult(KIO::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
00297
00298
00299
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
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 Q_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
00336
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
00365
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
00405 for ( KMMessage* msg = msgList.first(); msg; msg = msgList.next() )
00406 msg->setTransferInProgress(true);
00407
00408 if (folder() == msgParent)
00409 {
00410
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
00430 TQValueList<ulong> uids;
00431 getUids(msgList, uids);
00432
00433
00434 TQStringList sets = makeSets(uids, false);
00435
00436 for ( TQStringList::Iterator it = sets.begin(); it != sets.end(); ++it )
00437 {
00438
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
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 }
00470 }
00471
00472 if ( !msgList.isEmpty() )
00473 {
00474
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::null, ImapJob::tPutMessage, this );
00484 if ( !mAddMessageProgressItem && msgList.count() > 1 )
00485 {
00486
00487
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() )
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
00523
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
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
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
00565 temp_msgs.append(msg);
00566 uid.setNum( msg->UID() );
00567
00568 msgList.remove(msg);
00569 if (uid == last_uid) break;
00570 }
00571 }
00572 else
00573 {
00574
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
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
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
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
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
00671
00672 TQString name = jobData.path.mid( 1, jobData.path.length()-2 );
00673 name.remove( account()->delimiterForNamespace( name ) );
00674 if ( name.isEmpty() ) {
00675
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
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
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
00745 slotListNamespaces();
00746 return true;
00747 }
00748 mSubfolderState = imapListingInProgress;
00749
00750
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
00776
00777
00778
00779 kmkernel->imapFolderMgr()->quiet(true);
00780
00781 bool root = ( this == account()->rootFolder() );
00782 folder()->createChildFolder();
00783 if ( root && !account()->hasInbox() )
00784 {
00785
00786 initInbox();
00787 }
00788
00789
00790
00791
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
00802 TQStringList list;
00803 checkFolders( list, jobData.curNamespace );
00804
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
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
00846 if ( f->imapPath().isEmpty() ) {
00847 settingsChanged = true;
00848 }
00849
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
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 }
00877
00878
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::null );
00909 }
00910
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
00921 parent = parent.right( parent.length() - 1 );
00922 if ( parent != label() )
00923 {
00924 KMFolderNode *node = folder()->child()->first();
00925
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
00954
00955 bool isInNamespace = ( myNamespace.isEmpty() ||
00956 myNamespace == account()->namespaceForFolder( imapFld ) );
00957 kdDebug(5006) << node->name() << " in namespace " << myNamespace << ":" <<
00958 isInNamespace << endl;
00959
00960 TQString name = node->name();
00961 bool ignore = ( ( this == account()->rootFolder() ) &&
00962 ( imapFld->imapPath() == "/INBOX/" ||
00963 account()->isNamespaceFolder( name ) ||
00964 !isInNamespace ) );
00965
00966 if ( imapFld->imapPath().isEmpty() ) {
00967 ignore = false;
00968 }
00969 if ( !ignore )
00970 {
00971
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
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
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
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
01049
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
01056 if (mCheckingValidity) {
01057 kdDebug(5006) << "KMFolderImap::checkValidity - already checking" << endl;
01058 close("checkvalidity");
01059 return;
01060 }
01061
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 KIO::SimpleJob *job = KIO::get(url, false, false);
01080 KIO::Scheduler::assignJobToSlave(account()->slave(), job);
01081 account()->insertJob(job, jd);
01082 connect(job, TQT_SIGNAL(result(KIO::Job *)),
01083 TQT_SLOT(slotCheckValidityResult(KIO::Job *)));
01084 connect(job, TQT_SIGNAL(data(KIO::Job *, const TQByteArray &)),
01085 TQT_SLOT(slotSimpleData(KIO::Job *, const TQByteArray &)));
01086
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(KIO::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() != KIO::ERR_ACCESS_DENIED ) {
01116
01117
01118
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
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
01172 mMailCheckProgressItem->setTotalItems( exists );
01173 } else {
01174
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
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
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 KIO::SimpleJob *job = KIO::listDir(url, false);
01237 KIO::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(KIO::Job *)),
01242 this, TQT_SLOT(slotListFolderResult(KIO::Job *)));
01243 connect(job, TQT_SIGNAL(entries(KIO::Job *, const KIO::UDSEntryList &)),
01244 this, TQT_SLOT(slotListFolderEntries(KIO::Job *,
01245 const KIO::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 KIO::SimpleJob *newJob = KIO::get(url, false, false);
01253 KIO::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(KIO::Job *)),
01258 this, TQT_SLOT(slotGetLastMessagesResult(KIO::Job *)));
01259 connect(newJob, TQT_SIGNAL(data(KIO::Job *, const TQByteArray &)),
01260 this, TQT_SLOT(slotGetMessagesData(KIO::Job *, const TQByteArray &)));
01261 }
01262 }
01263
01264
01265
01266 void KMFolderImap::slotListFolderResult(KIO::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
01283
01284
01285
01286
01287
01288
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
01298
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
01306
01307
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;
01322 }
01323
01324
01325 while (idx < count()) removeMsg(idx, true);
01326 }
01327
01328 for (uid = (*it).items.begin(); uid != (*it).items.end(); ++uid)
01329 (*uid).truncate((*uid).find(","));
01330 ImapAccountBase::jobData jd( TQString::null, (*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
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);
01352
01353
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 KIO::SimpleJob *newJob = KIO::get(url, false, false);
01360 jd.url = url.url();
01361 KIO::Scheduler::assignJobToSlave(account()->slave(), newJob);
01362 account()->insertJob(newJob, jd);
01363 connect(newJob, TQT_SIGNAL(result(KIO::Job *)),
01364 this, (i == sets.at(sets.count() - 1))
01365 ? TQT_SLOT(slotGetLastMessagesResult(KIO::Job *))
01366 : TQT_SLOT(slotGetMessagesResult(KIO::Job *)));
01367 connect(newJob, TQT_SIGNAL(data(KIO::Job *, const TQByteArray &)),
01368 this, TQT_SLOT(slotGetMessagesData(KIO::Job *, const TQByteArray &)));
01369 }
01370 }
01371
01372
01373
01374 void KMFolderImap::slotListFolderEntries(KIO::Job * job,
01375 const KIO::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 (KIO::UDSEntryList::ConstIterator udsIt = uds.begin();
01382 udsIt != uds.end(); udsIt++)
01383 {
01384 for (KIO::UDSEntry::ConstIterator eIt = (*udsIt).begin();
01385 eIt != (*udsIt).end(); eIt++)
01386 {
01387 if ((*eIt).m_uds == KIO::UDS_NAME)
01388 name = (*eIt).m_str;
01389 else if ((*eIt).m_uds == KIO::UDS_MIME_TYPE)
01390 mimeType = (*eIt).m_str;
01391 else if ((*eIt).m_uds == KIO::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
01407
01408
01409
01410
01411
01412
01413
01414
01415
01416
01417
01418
01419
01420
01421
01422
01423
01424 void KMFolderImap::flagsToStatus(KMMsgBase *msg, int flags, bool newMsg, int supportedFlags )
01425 {
01426 if ( !msg ) return;
01427
01428
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
01466
01467
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
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(KIO::Job * job, const TQByteArray & data)
01523 {
01524 if ( data.isEmpty() ) return;
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
01531
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::null );
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
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
01584 ok = false;
01585 }
01586
01587 if ( flags & 8 )
01588 ok = false;
01589 if ( !ok ) {
01590 delete msg;
01591 msg = 0;
01592 } else {
01593 if ( serNum > 0 ) {
01594
01595 msg->setMsgSerNum( serNum );
01596 }
01597
01598 if ( md ) {
01599 msg->setStatus( md->status() );
01600 } else if ( !account()->hasCapability("uidplus") ) {
01601
01602
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
01616 flagsToStatus((KMMsgBase*)msg, flags, true, mUploadAllFlags ? 31 : mPermanentFlags);
01617
01618 msg->setMsgSizeServer( msg->headerField("X-Length").toUInt() );
01619 msg->setUID(uid);
01620 if ( msg->getMsgSerNum() > 0 ) {
01621 saveMsgMetaData( msg );
01622 }
01623
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 }
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
01660
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
01669 if ( partSpecifier == "STRUCTURE" )
01670 partSpecifier = TQString::null;
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(KIO::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(KIO::Job * job)
01708 {
01709 getMessagesResult(job, true);
01710 }
01711
01712
01713
01714 void KMFolderImap::slotGetMessagesResult(KIO::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 KIO::SimpleJob *job = KIO::mkdir(url);
01739 KIO::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(KIO::Job *)),
01744 this, TQT_SLOT(slotCreateFolderResult(KIO::Job *)));
01745 }
01746
01747
01748
01749 void KMFolderImap::slotCreateFolderResult(KIO::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() == KIO::ERR_COULD_NOT_MKDIR ) {
01761
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(KIO::Job * job, const TQByteArray & data)
01811 {
01812 if ( data.isEmpty() ) return;
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
01830
01831
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 KIO::SimpleJob *job = KIO::file_delete(url, false);
01841 KIO::Scheduler::assignJobToSlave(account()->slave(), job);
01842 ImapAccountBase::jobData jd( url.url(), 0 );
01843 account()->insertJob(job, jd);
01844 connect(job, TQT_SIGNAL(result(KIO::Job *)),
01845 account(), TQT_SLOT(slotSimpleResult(KIO::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
01868
01869 if ( uid.isEmpty() ) continue;
01870 url.setPath(msg_parent->imapPath() + ";UID=" + uid);
01871 if ( account()->makeConnection() != ImapAccountBase::Connected )
01872 return;
01873 KIO::SimpleJob *job = KIO::file_delete(url, false);
01874 KIO::Scheduler::assignJobToSlave(account()->slave(), job);
01875 ImapAccountBase::jobData jd( url.url(), 0 );
01876 account()->insertJob(job, jd);
01877 connect(job, TQT_SIGNAL(result(KIO::Job *)),
01878 account(), TQT_SLOT(slotSimpleResult(KIO::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
01904
01905
01906
01907
01908
01909
01910
01911
01912
01913
01914 if ( mReadOnly ) {
01915
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
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
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
01968
01969
01970 kdDebug(5006) << "Set status during folder listing, restarting listing." << endl;
01971 disconnect(this, TQT_SLOT(slotListFolderResult(KIO::Job *)));
01972 quiet( false );
01973 reallyGetFolder( TQString::null );
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
02001 bool inserted = false;
02002
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
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
02021 sets.append(set);
02022 set = "";
02023 }
02024 } else {
02025 inserted = false;
02026 }
02027 }
02028 last = *it;
02029 }
02030
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
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 KIO::SimpleJob *job = KIO::file_delete(url, false);
02074 KIO::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(KIO::Job *)),
02079 account(), TQT_SLOT(slotSimpleResult(KIO::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
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
02105 setAlreadyRemoved( true );
02106 kmkernel->imapFolderMgr()->remove( folder() );
02107 return false;
02108 }
02109
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
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 KIO::SimpleJob *job = KIO::stat(url, false);
02136 KIO::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(KIO::Job *)),
02141 TQT_SLOT(slotStatResult(KIO::Job *)));
02142 return true;
02143 }
02144
02145
02146
02147 void KMFolderImap::slotStatResult(KIO::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 KIO::UDSEntry uds = static_cast<KIO::StatJob*>(job)->statResult();
02158 for (KIO::UDSEntry::ConstIterator it = uds.begin(); it != uds.end(); it++)
02159 {
02160 if ((*it).m_uds == KIO::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
02188 TQString buffer = TQString::null;
02189 int setstart = -1;
02190
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
02199 for (int j = setstart; j <= buffer.toInt(); j++)
02200 {
02201 uidlist.append(j);
02202 }
02203 setstart = -1;
02204 } else {
02205
02206 uidlist.append(buffer.toInt());
02207 }
02208 buffer = "";
02209 } else if (chr == ':') {
02210
02211 setstart = buffer.toInt();
02212 buffer = "";
02213 } else if (chr.category() == TQChar::Number_DecimalDigit) {
02214
02215 buffer += chr;
02216 } else {
02217
02218 }
02219 }
02220
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
02238 int rc = KMFolderMbox::expungeContents();
02239
02240
02241 KURL url = account()->getUrl();
02242 url.setPath( imapPath() + ";UID=1:*");
02243 if ( account()->makeConnection() == ImapAccountBase::Connected )
02244 {
02245 KIO::SimpleJob *job = KIO::file_delete(url, false);
02246 KIO::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(KIO::Job *)),
02251 account(), TQT_SLOT(slotSimpleResult(KIO::Job *)));
02252 }
02253
02254
02255
02256
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
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
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
02348 TQValueList<Q_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<Q_UINT32>, const KMSearchPattern*, bool ) ),
02354 this, TQT_SLOT( slotSearchDone( TQValueList<Q_UINT32>, const KMSearchPattern*, bool ) ) );
02355 job->start();
02356 }
02357
02358
02359 void KMFolderImap::slotSearchDone( TQValueList<Q_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, Q_UINT32 serNum )
02368 {
02369 if ( !pattern || pattern->isEmpty() )
02370 {
02371
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( Q_UINT32, const KMSearchPattern*, bool ) ),
02377 this, TQT_SLOT( slotSearchDone( Q_UINT32, const KMSearchPattern*, bool ) ) );
02378 job->start();
02379 }
02380
02381
02382 void KMFolderImap::slotSearchDone( Q_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"