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 <qbuffer.h>
00059 #include <qtextcodec.h>
00060 #include <qstylesheet.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 mAlreadyRemoved = false;
00078 mHasChildren = ChildrenUnknown;
00079 mMailCheckProgressItem = 0;
00080 mListDirProgressItem = 0;
00081 mAddMessageProgressItem = 0;
00082 mReadOnly = false;
00083
00084 connect (this, SIGNAL( folderComplete( KMFolderImap*, bool ) ),
00085 this, SLOT( slotCompleteMailCheckProgress()) );
00086 }
00087
00088 KMFolderImap::~KMFolderImap()
00089 {
00090 if (mAccount) {
00091 mAccount->removeSlaveJobsForFolder( folder() );
00092
00093
00094
00095
00096 if ( mAccount->checkingMail( folder() ) ) {
00097 mAccount->killAllJobs();
00098 }
00099 }
00100 writeConfig();
00101 if (kmkernel->undoStack()) kmkernel->undoStack()->folderDestroyed( folder() );
00102 mMetaDataMap.setAutoDelete( true );
00103 mMetaDataMap.clear();
00104 mUidMetaDataMap.setAutoDelete( true );
00105 mUidMetaDataMap.clear();
00106 }
00107
00108
00109
00110 void KMFolderImap::reallyDoClose(const char* owner)
00111 {
00112 if (isSelected()) {
00113 kdWarning(5006) << "Trying to close the selected folder " << label() <<
00114 " - ignoring!" << endl;
00115 return;
00116 }
00117
00118
00119 if (account())
00120 account()->ignoreJobsForFolder( folder() );
00121 int idx = count();
00122 while (--idx >= 0) {
00123 if ( mMsgList[idx]->isMessage() ) {
00124 KMMessage *msg = static_cast<KMMessage*>(mMsgList[idx]);
00125 if (msg->transferInProgress())
00126 msg->setTransferInProgress( false );
00127 }
00128 }
00129 KMFolderMbox::reallyDoClose( owner );
00130 }
00131
00132 KMFolder* KMFolderImap::trashFolder() const
00133 {
00134 QString trashStr = account()->trash();
00135 return kmkernel->imapFolderMgr()->findIdString( trashStr );
00136 }
00137
00138
00139 KMMessage* KMFolderImap::getMsg(int idx)
00140 {
00141 if(!(idx >= 0 && idx <= count()))
00142 return 0;
00143
00144 KMMsgBase* mb = getMsgBase(idx);
00145 if (!mb) return 0;
00146 if (mb->isMessage())
00147 {
00148 return ((KMMessage*)mb);
00149 } else {
00150 KMMessage* msg = FolderStorage::getMsg( idx );
00151 if ( msg )
00152 msg->setComplete( false );
00153 return msg;
00154 }
00155 }
00156
00157
00158 KMAcctImap* KMFolderImap::account() const
00159 {
00160 if ( !mAccount ) {
00161 KMFolderDir *parentFolderDir = dynamic_cast<KMFolderDir*>( folder()->parent() );
00162 if ( !parentFolderDir ) {
00163 kdWarning() << k_funcinfo << "No parent folder dir found for " << name() << endl;
00164 return 0;
00165 }
00166 KMFolder *parentFolder = parentFolderDir->owner();
00167 if ( !parentFolder ) {
00168 kdWarning() << k_funcinfo << "No parent folder found for " << name() << endl;
00169 return 0;
00170 }
00171 KMFolderImap *parentStorage = dynamic_cast<KMFolderImap*>( parentFolder->storage() );
00172 if ( parentStorage )
00173 mAccount = parentStorage->account();
00174 }
00175 return mAccount;
00176 }
00177
00178 void KMFolderImap::setAccount(KMAcctImap *aAccount)
00179 {
00180 mAccount = aAccount;
00181 if( !folder() || !folder()->child() ) return;
00182 KMFolderNode* node;
00183 for (node = folder()->child()->first(); node;
00184 node = folder()->child()->next())
00185 {
00186 if (!node->isDir())
00187 static_cast<KMFolderImap*>(static_cast<KMFolder*>(node)->storage())->setAccount(aAccount);
00188 }
00189 }
00190
00191
00192 void KMFolderImap::readConfig()
00193 {
00194 KConfig* config = KMKernel::config();
00195 KConfigGroupSaver saver(config, "Folder-" + folder()->idString());
00196 mCheckMail = config->readBoolEntry("checkmail", true);
00197
00198 mUidValidity = config->readEntry("UidValidity");
00199 if ( mImapPath.isEmpty() ) {
00200 setImapPath( config->readEntry("ImapPath") );
00201 }
00202 if (QString(name()).upper() == "INBOX" && mImapPath == "/INBOX/")
00203 {
00204 folder()->setSystemFolder( true );
00205 folder()->setLabel( i18n("inbox") );
00206 }
00207 mNoContent = config->readBoolEntry("NoContent", false);
00208 mReadOnly = config->readBoolEntry("ReadOnly", false);
00209 mUploadAllFlags = config->readBoolEntry( "UploadAllFlags", true );
00210 mPermanentFlags = config->readNumEntry( "PermanentFlags", 31 );
00211
00212 KMFolderMbox::readConfig();
00213 }
00214
00215
00216 void KMFolderImap::writeConfig()
00217 {
00218 KConfig* config = KMKernel::config();
00219 KConfigGroupSaver saver(config, "Folder-" + folder()->idString());
00220 config->writeEntry("checkmail", mCheckMail);
00221 config->writeEntry("UidValidity", mUidValidity);
00222 config->writeEntry("ImapPath", mImapPath);
00223 config->writeEntry("NoContent", mNoContent);
00224 config->writeEntry("ReadOnly", mReadOnly);
00225 config->writeEntry( "UploadAllFlags", mUploadAllFlags );
00226 config->writeEntry( "PermanentFlags", mPermanentFlags );
00227 KMFolderMbox::writeConfig();
00228 }
00229
00230
00231 void KMFolderImap::remove()
00232 {
00233 if ( mAlreadyRemoved || !account() )
00234 {
00235
00236 FolderStorage::remove();
00237 return;
00238 }
00239 KURL url = account()->getUrl();
00240 url.setPath(imapPath());
00241 if ( account()->makeConnection() == ImapAccountBase::Error ||
00242 imapPath().isEmpty() )
00243 {
00244 emit removed(folder(), false);
00245 return;
00246 }
00247 KIO::SimpleJob *job = KIO::file_delete(url, false);
00248 KIO::Scheduler::assignJobToSlave(account()->slave(), job);
00249 ImapAccountBase::jobData jd(url.url());
00250 jd.progressItem = ProgressManager::createProgressItem(
00251 "ImapFolderRemove" + ProgressManager::getUniqueID(),
00252 i18n("Removing folder"),
00253 i18n( "URL: %1" ).arg( QStyleSheet::escape( folder()->prettyURL() ) ),
00254 false,
00255 account()->useSSL() || account()->useTLS() );
00256 account()->insertJob(job, jd);
00257 connect(job, SIGNAL(result(KIO::Job *)),
00258 this, SLOT(slotRemoveFolderResult(KIO::Job *)));
00259 }
00260
00261
00262 void KMFolderImap::slotRemoveFolderResult(KIO::Job *job)
00263 {
00264 ImapAccountBase::JobIterator it = account()->findJob(job);
00265 if ( it == account()->jobsEnd() ) return;
00266 if (job->error())
00267 {
00268 account()->handleJobError( job, i18n("Error while removing a folder.") );
00269 emit removed(folder(), false);
00270 } else {
00271 account()->removeJob(it);
00272 FolderStorage::remove();
00273 }
00274
00275 }
00276
00277
00278 void KMFolderImap::removeMsg(int idx, bool quiet)
00279 {
00280 if (idx < 0)
00281 return;
00282
00283 if (!quiet)
00284 {
00285 KMMessage *msg = getMsg(idx);
00286 deleteMessage(msg);
00287 }
00288
00289 mLastUid = 0;
00290 KMFolderMbox::removeMsg(idx);
00291 }
00292
00293 void KMFolderImap::removeMsg( const QPtrList<KMMessage>& msgList, bool quiet )
00294 {
00295 if ( msgList.isEmpty() ) return;
00296 if (!quiet)
00297 deleteMessage(msgList);
00298
00299 mLastUid = 0;
00300
00301
00302
00303
00304
00305
00306 QPtrListIterator<KMMessage> it( msgList );
00307 KMMessage *msg;
00308 while ( (msg = it.current()) != 0 ) {
00309 ++it;
00310 int idx = find(msg);
00311 assert( idx != -1);
00312
00313 KMFolderMbox::removeMsg(idx, quiet);
00314 }
00315 }
00316
00317
00318 int KMFolderImap::rename( const QString& newName, KMFolderDir *aParent )
00319 {
00320 if ( !aParent )
00321 KMFolderMbox::rename( newName );
00322 kmkernel->folderMgr()->contentsChanged();
00323 return 0;
00324 }
00325
00326
00327 void KMFolderImap::addMsgQuiet(KMMessage* aMsg)
00328 {
00329 KMFolder *aFolder = aMsg->parent();
00330 Q_UINT32 serNum = 0;
00331 aMsg->setTransferInProgress( false );
00332 if (aFolder) {
00333 serNum = aMsg->getMsgSerNum();
00334 kmkernel->undoStack()->pushSingleAction( serNum, aFolder, folder() );
00335 int idx = aFolder->find( aMsg );
00336 assert( idx != -1 );
00337 aFolder->take( idx );
00338 } else {
00339 kdDebug(5006) << k_funcinfo << "no parent" << endl;
00340 }
00341 if ( !account()->hasCapability("uidplus") ) {
00342
00343
00344 mMetaDataMap.insert( aMsg->msgIdMD5(),
00345 new KMMsgMetaData(aMsg->status(), serNum) );
00346 }
00347
00348 delete aMsg;
00349 aMsg = 0;
00350 getFolder();
00351 }
00352
00353
00354 void KMFolderImap::addMsgQuiet(QPtrList<KMMessage> msgList)
00355 {
00356 if ( mAddMessageProgressItem )
00357 {
00358 mAddMessageProgressItem->setComplete();
00359 mAddMessageProgressItem = 0;
00360 }
00361 KMFolder *aFolder = msgList.first()->parent();
00362 int undoId = -1;
00363 bool uidplus = account()->hasCapability("uidplus");
00364 for ( KMMessage* msg = msgList.first(); msg; msg = msgList.next() )
00365 {
00366 if ( undoId == -1 )
00367 undoId = kmkernel->undoStack()->newUndoAction( aFolder, folder() );
00368 if ( msg->getMsgSerNum() > 0 )
00369 kmkernel->undoStack()->addMsgToAction( undoId, msg->getMsgSerNum() );
00370 if ( !uidplus ) {
00371
00372
00373 mMetaDataMap.insert( msg->msgIdMD5(),
00374 new KMMsgMetaData(msg->status(), msg->getMsgSerNum()) );
00375 }
00376 msg->setTransferInProgress( false );
00377 }
00378 if ( aFolder ) {
00379 aFolder->take( msgList );
00380 } else {
00381 kdDebug(5006) << k_funcinfo << "no parent" << endl;
00382 }
00383 msgList.setAutoDelete(true);
00384 msgList.clear();
00385 getFolder();
00386 }
00387
00388
00389 int KMFolderImap::addMsg(KMMessage* aMsg, int* aIndex_ret)
00390 {
00391 QPtrList<KMMessage> list;
00392 list.append(aMsg);
00393 QValueList<int> index;
00394 int ret = addMsg(list, index);
00395 aIndex_ret = &index.first();
00396 return ret;
00397 }
00398
00399 int KMFolderImap::addMsg(QPtrList<KMMessage>& msgList, QValueList<int>& aIndex_ret)
00400 {
00401 KMMessage *aMsg = msgList.getFirst();
00402 KMFolder *msgParent = aMsg->parent();
00403
00404 ImapJob *imapJob = 0;
00405 if (msgParent)
00406 {
00407 if (msgParent->folderType() == KMFolderTypeImap)
00408 {
00409 if (static_cast<KMFolderImap*>(msgParent->storage())->account() == account())
00410 {
00411
00412 for ( KMMessage* msg = msgList.first(); msg; msg = msgList.next() )
00413 msg->setTransferInProgress(true);
00414
00415 if (folder() == msgParent)
00416 {
00417
00418 for ( KMMessage* msg = msgList.first(); msg; msg = msgList.next() )
00419 {
00420 if (!msg->isComplete())
00421 {
00422 int idx = msgParent->find(msg);
00423 assert(idx != -1);
00424 msg = msgParent->getMsg(idx);
00425 }
00426 imapJob = new ImapJob(msg, ImapJob::tPutMessage, this);
00427 connect(imapJob, SIGNAL(messageStored(KMMessage*)),
00428 SLOT(addMsgQuiet(KMMessage*)));
00429 connect(imapJob, SIGNAL(result(KMail::FolderJob*)),
00430 SLOT(slotCopyMsgResult(KMail::FolderJob*)));
00431 imapJob->start();
00432 }
00433
00434 } else {
00435
00436
00437 QValueList<ulong> uids;
00438 getUids(msgList, uids);
00439
00440
00441 QStringList sets = makeSets(uids, false);
00442
00443 for ( QStringList::Iterator it = sets.begin(); it != sets.end(); ++it )
00444 {
00445
00446 QPtrList<KMMessage> temp_msgs = splitMessageList(*it, msgList);
00447 if ( temp_msgs.isEmpty() ) kdDebug(5006) << "Wow! KMFolderImap::splitMessageList() returned an empty list!" << endl;
00448 imapJob = new ImapJob(temp_msgs, *it, ImapJob::tMoveMessage, this);
00449 connect(imapJob, SIGNAL(messageCopied(QPtrList<KMMessage>)),
00450 SLOT(addMsgQuiet(QPtrList<KMMessage>)));
00451 connect(imapJob, SIGNAL(result(KMail::FolderJob*)),
00452 SLOT(slotCopyMsgResult(KMail::FolderJob*)));
00453 imapJob->start();
00454 }
00455 }
00456 return 0;
00457 }
00458 else
00459 {
00460
00461 QPtrListIterator<KMMessage> it( msgList );
00462 KMMessage *msg;
00463 while ( (msg = it.current()) != 0 )
00464 {
00465 ++it;
00466 int index;
00467 if (!canAddMsgNow(msg, &index)) {
00468 aIndex_ret << index;
00469 msgList.remove(msg);
00470 } else {
00471 if (!msg->transferInProgress())
00472 msg->setTransferInProgress(true);
00473 }
00474 }
00475 }
00476 }
00477 }
00478
00479 if ( !msgList.isEmpty() )
00480 {
00481
00482 QPtrListIterator<KMMessage> it( msgList );
00483 KMMessage* msg;
00484 while ( ( msg = it.current() ) != 0 )
00485 {
00486 ++it;
00487 if ( !msg->transferInProgress() )
00488 msg->setTransferInProgress( true );
00489 }
00490 imapJob = new ImapJob( msgList, QString::null, ImapJob::tPutMessage, this );
00491 if ( !mAddMessageProgressItem && msgList.count() > 1 )
00492 {
00493
00494
00495 mAddMessageProgressItem = ProgressManager::createProgressItem(
00496 "Uploading"+ProgressManager::getUniqueID(),
00497 i18n("Uploading message data"),
00498 i18n("Destination folder: %1").arg( QStyleSheet::escape( folder()->prettyURL() ) ),
00499 true,
00500 account()->useSSL() || account()->useTLS() );
00501 mAddMessageProgressItem->setTotalItems( msgList.count() );
00502 connect ( mAddMessageProgressItem, SIGNAL( progressItemCanceled( KPIM::ProgressItem*)),
00503 account(), SLOT( slotAbortRequested( KPIM::ProgressItem* ) ) );
00504 imapJob->setParentProgressItem( mAddMessageProgressItem );
00505 }
00506 connect( imapJob, SIGNAL( messageCopied(QPtrList<KMMessage>) ),
00507 SLOT( addMsgQuiet(QPtrList<KMMessage>) ) );
00508 connect( imapJob, SIGNAL(result(KMail::FolderJob*)),
00509 SLOT(slotCopyMsgResult(KMail::FolderJob*)) );
00510 imapJob->start();
00511 }
00512
00513 return 0;
00514 }
00515
00516
00517 void KMFolderImap::slotCopyMsgResult( KMail::FolderJob* job )
00518 {
00519 kdDebug(5006) << k_funcinfo << job->error() << endl;
00520 if ( job->error() )
00521 emit folderComplete( this, false );
00522 }
00523
00524
00525 void KMFolderImap::copyMsg(QPtrList<KMMessage>& msgList)
00526 {
00527 if ( !account()->hasCapability("uidplus") ) {
00528 for ( KMMessage *msg = msgList.first(); msg; msg = msgList.next() ) {
00529
00530
00531 mMetaDataMap.insert( msg->msgIdMD5(), new KMMsgMetaData(msg->status()) );
00532 }
00533 }
00534
00535 QValueList<ulong> uids;
00536 getUids(msgList, uids);
00537 QStringList sets = makeSets(uids, false);
00538 for ( QStringList::Iterator it = sets.begin(); it != sets.end(); ++it )
00539 {
00540
00541 QPtrList<KMMessage> temp_msgs = splitMessageList(*it, msgList);
00542
00543 ImapJob *job = new ImapJob(temp_msgs, *it, ImapJob::tCopyMessage, this);
00544 connect(job, SIGNAL(result(KMail::FolderJob*)),
00545 SLOT(slotCopyMsgResult(KMail::FolderJob*)));
00546 job->start();
00547 }
00548 }
00549
00550
00551 QPtrList<KMMessage> KMFolderImap::splitMessageList(const QString& set,
00552 QPtrList<KMMessage>& msgList)
00553 {
00554 int lastcomma = set.findRev(",");
00555 int lastdub = set.findRev(":");
00556 int last = 0;
00557 if (lastdub > lastcomma) last = lastdub;
00558 else last = lastcomma;
00559 last++;
00560 if (last < 0) last = set.length();
00561
00562 const QString last_uid = set.right(set.length() - last);
00563 QPtrList<KMMessage> temp_msgs;
00564 QString uid;
00565 if (!last_uid.isEmpty())
00566 {
00567 QPtrListIterator<KMMessage> it( msgList );
00568 KMMessage* msg = 0;
00569 while ( (msg = it.current()) != 0 )
00570 {
00571
00572 temp_msgs.append(msg);
00573 uid.setNum( msg->UID() );
00574
00575 msgList.remove(msg);
00576 if (uid == last_uid) break;
00577 }
00578 }
00579 else
00580 {
00581
00582 temp_msgs = msgList;
00583 }
00584
00585 return temp_msgs;
00586 }
00587
00588
00589 KMMessage* KMFolderImap::take(int idx)
00590 {
00591 KMMsgBase* mb(mMsgList[idx]);
00592 if (!mb) return 0;
00593 if (!mb->isMessage()) readMsg(idx);
00594
00595 KMMessage *msg = static_cast<KMMessage*>(mb);
00596 deleteMessage(msg);
00597
00598 mLastUid = 0;
00599 return KMFolderMbox::take(idx);
00600 }
00601
00602 void KMFolderImap::take(QPtrList<KMMessage> msgList)
00603 {
00604 deleteMessage(msgList);
00605
00606 mLastUid = 0;
00607 KMFolderMbox::take(msgList);
00608 }
00609
00610
00611 void KMFolderImap::slotListNamespaces()
00612 {
00613 disconnect( account(), SIGNAL( connectionResult(int, const QString&) ),
00614 this, SLOT( slotListNamespaces() ) );
00615 if ( account()->makeConnection() == ImapAccountBase::Error )
00616 {
00617 kdWarning(5006) << "slotListNamespaces - got no connection" << endl;
00618 return;
00619 } else if ( account()->makeConnection() == ImapAccountBase::Connecting )
00620 {
00621
00622 kdDebug(5006) << "slotListNamespaces - waiting for connection" << endl;
00623 connect( account(), SIGNAL( connectionResult(int, const QString&) ),
00624 this, SLOT( slotListNamespaces() ) );
00625 return;
00626 }
00627 kdDebug(5006) << "slotListNamespaces" << endl;
00628
00629 setSubfolderState( imapNoInformation );
00630 mSubfolderState = imapListingInProgress;
00631 account()->setHasInbox( false );
00632
00633 ImapAccountBase::ListType type = ImapAccountBase::List;
00634 if ( account()->onlySubscribedFolders() )
00635 type = ImapAccountBase::ListSubscribed;
00636
00637 ImapAccountBase::nsMap map = account()->namespaces();
00638 QStringList personal = map[ImapAccountBase::PersonalNS];
00639
00640 for ( QStringList::Iterator it = personal.begin(); it != personal.end(); ++it )
00641 {
00642 KMail::ListJob* job = new KMail::ListJob( account(), type, this,
00643 account()->addPathToNamespace( *it ) );
00644 job->setNamespace( *it );
00645 job->setHonorLocalSubscription( true );
00646 connect( job, SIGNAL(receivedFolders(const QStringList&, const QStringList&,
00647 const QStringList&, const QStringList&, const ImapAccountBase::jobData&)),
00648 this, SLOT(slotListResult(const QStringList&, const QStringList&,
00649 const QStringList&, const QStringList&, const ImapAccountBase::jobData&)));
00650 job->start();
00651 }
00652
00653
00654 QStringList ns = map[ImapAccountBase::OtherUsersNS];
00655 ns += map[ImapAccountBase::SharedNS];
00656 for ( QStringList::Iterator it = ns.begin(); it != ns.end(); ++it )
00657 {
00658 KMail::ListJob* job = new KMail::ListJob( account(), type, this, account()->addPathToNamespace( *it ) );
00659 job->setHonorLocalSubscription( true );
00660 connect( job, SIGNAL(receivedFolders(const QStringList&, const QStringList&,
00661 const QStringList&, const QStringList&, const ImapAccountBase::jobData&)),
00662 this, SLOT(slotCheckNamespace(const QStringList&, const QStringList&,
00663 const QStringList&, const QStringList&, const ImapAccountBase::jobData&)));
00664 job->start();
00665 }
00666 }
00667
00668
00669 void KMFolderImap::slotCheckNamespace( const QStringList& subfolderNames,
00670 const QStringList& subfolderPaths,
00671 const QStringList& subfolderMimeTypes,
00672 const QStringList& subfolderAttributes,
00673 const ImapAccountBase::jobData& jobData )
00674 {
00675 kdDebug(5006) << "slotCheckNamespace - " << subfolderNames.join(",") << endl;
00676
00677
00678
00679 QString name = jobData.path.mid( 1, jobData.path.length()-2 );
00680 name.remove( account()->delimiterForNamespace( name ) );
00681 if ( name.isEmpty() ) {
00682
00683 slotListResult( subfolderNames, subfolderPaths,
00684 subfolderMimeTypes, subfolderAttributes, jobData );
00685 return;
00686 }
00687
00688 folder()->createChildFolder();
00689 KMFolderNode *node = 0;
00690 for ( node = folder()->child()->first(); node;
00691 node = folder()->child()->next())
00692 {
00693 if ( !node->isDir() && node->name() == name )
00694 break;
00695 }
00696 if ( subfolderNames.isEmpty() )
00697 {
00698 if ( node )
00699 {
00700 kdDebug(5006) << "delete namespace folder " << name << endl;
00701 KMFolder *fld = static_cast<KMFolder*>(node);
00702 KMFolderImap* nsFolder = static_cast<KMFolderImap*>(fld->storage());
00703 nsFolder->setAlreadyRemoved( true );
00704 kmkernel->imapFolderMgr()->remove( fld );
00705 }
00706 } else {
00707 if ( node )
00708 {
00709
00710 kdDebug(5006) << "found namespace folder " << name << endl;
00711 if ( !account()->listOnlyOpenFolders() )
00712 {
00713 KMFolderImap* nsFolder =
00714 static_cast<KMFolderImap*>(static_cast<KMFolder*>(node)->storage());
00715 nsFolder->slotListResult( subfolderNames, subfolderPaths,
00716 subfolderMimeTypes, subfolderAttributes, jobData );
00717 }
00718 } else
00719 {
00720
00721 kdDebug(5006) << "create namespace folder " << name << endl;
00722 KMFolder *fld = folder()->child()->createFolder( name );
00723 if ( fld ) {
00724 KMFolderImap* f = static_cast<KMFolderImap*> ( fld->storage() );
00725 f->initializeFrom( this, account()->addPathToNamespace( name ),
00726 "inode/directory" );
00727 f->close( "kmfolderimap_create" );
00728 if ( !account()->listOnlyOpenFolders() )
00729 {
00730 f->slotListResult( subfolderNames, subfolderPaths,
00731 subfolderMimeTypes, subfolderAttributes, jobData );
00732 }
00733 }
00734 kmkernel->imapFolderMgr()->contentsChanged();
00735 }
00736 }
00737 }
00738
00739
00740 bool KMFolderImap::listDirectory()
00741 {
00742 if ( !account() ||
00743 ( account() && account()->makeConnection() == ImapAccountBase::Error ) )
00744 {
00745 kdDebug(5006) << "KMFolderImap::listDirectory - got no connection" << endl;
00746 return false;
00747 }
00748
00749 if ( this == account()->rootFolder() )
00750 {
00751
00752 slotListNamespaces();
00753 return true;
00754 }
00755 mSubfolderState = imapListingInProgress;
00756
00757
00758 ImapAccountBase::ListType type = ImapAccountBase::List;
00759 if ( account()->onlySubscribedFolders() )
00760 type = ImapAccountBase::ListSubscribed;
00761 KMail::ListJob* job = new KMail::ListJob( account(), type, this );
00762 job->setParentProgressItem( account()->listDirProgressItem() );
00763 job->setHonorLocalSubscription( true );
00764 connect( job, SIGNAL(receivedFolders(const QStringList&, const QStringList&,
00765 const QStringList&, const QStringList&, const ImapAccountBase::jobData&)),
00766 this, SLOT(slotListResult(const QStringList&, const QStringList&,
00767 const QStringList&, const QStringList&, const ImapAccountBase::jobData&)));
00768 job->start();
00769
00770 return true;
00771 }
00772
00773
00774
00775 void KMFolderImap::slotListResult( const QStringList& subfolderNames,
00776 const QStringList& subfolderPaths,
00777 const QStringList& subfolderMimeTypes,
00778 const QStringList& subfolderAttributes,
00779 const ImapAccountBase::jobData& jobData )
00780 {
00781 mSubfolderState = imapFinished;
00782
00783
00784
00785
00786 kmkernel->imapFolderMgr()->quiet(true);
00787
00788 bool root = ( this == account()->rootFolder() );
00789 folder()->createChildFolder();
00790 if ( root && !account()->hasInbox() )
00791 {
00792
00793 initInbox();
00794 }
00795
00796
00797
00798
00799 if ( root && !subfolderNames.empty() )
00800 {
00801 KMFolderImap* parent = findParent( subfolderPaths.first(), subfolderNames.first() );
00802 if ( parent )
00803 {
00804 kdDebug(5006) << "KMFolderImap::slotListResult - pass listing to "
00805 << parent->label() << endl;
00806 parent->slotListResult( subfolderNames, subfolderPaths,
00807 subfolderMimeTypes, subfolderAttributes, jobData );
00808
00809 QStringList list;
00810 checkFolders( list, jobData.curNamespace );
00811
00812 emit directoryListingFinished( this );
00813 kmkernel->imapFolderMgr()->quiet( false );
00814 return;
00815 }
00816 }
00817
00818 bool emptyList = ( root && subfolderNames.empty() );
00819 if ( !emptyList )
00820 {
00821 checkFolders( subfolderNames, jobData.curNamespace );
00822 }
00823
00824 KMFolderImap *f = 0;
00825 KMFolderNode *node = 0;
00826 for ( uint i = 0; i < subfolderNames.count(); i++ )
00827 {
00828 bool settingsChanged = false;
00829
00830 for ( node = folder()->child()->first(); node;
00831 node = folder()->child()->next() ) {
00832 if ( !node->isDir() && node->name() == subfolderNames[i] )
00833 break;
00834 }
00835 if ( node ) {
00836 f = static_cast<KMFolderImap*>(static_cast<KMFolder*>(node)->storage());
00837 }
00838 else if ( subfolderPaths[i].upper() != "/INBOX/" )
00839 {
00840 kdDebug(5006) << "create folder " << subfolderNames[i] << endl;
00841 KMFolder *fld = folder()->child()->createFolder(subfolderNames[i]);
00842 if ( fld ) {
00843 f = static_cast<KMFolderImap*> ( fld->storage() );
00844 f->close( "kmfolderimap_create" );
00845 settingsChanged = true;
00846 } else {
00847 kdWarning(5006) << "can't create folder " << subfolderNames[i] << endl;
00848 }
00849 }
00850 if ( f )
00851 {
00852
00853 if ( f->imapPath().isEmpty() ) {
00854 settingsChanged = true;
00855 }
00856
00857 account()->listDirProgressItem()->incCompletedItems();
00858 account()->listDirProgressItem()->updateProgress();
00859 account()->listDirProgressItem()->setStatus( folder()->prettyURL() + i18n(" completed") );
00860
00861 f->initializeFrom( this, subfolderPaths[i], subfolderMimeTypes[i] );
00862 f->setChildrenState( subfolderAttributes[i] );
00863 if ( account()->listOnlyOpenFolders() &&
00864 f->hasChildren() != FolderStorage::ChildrenUnknown )
00865 {
00866 settingsChanged = true;
00867 }
00868
00869 if ( settingsChanged )
00870 {
00871
00872 kmkernel->imapFolderMgr()->contentsChanged();
00873 }
00874 if ( ( subfolderMimeTypes[i] == "message/directory" ||
00875 subfolderMimeTypes[i] == "inode/directory" ) &&
00876 !account()->listOnlyOpenFolders() )
00877 {
00878 f->listDirectory();
00879 }
00880 } else {
00881 kdWarning(5006) << "can't find folder " << subfolderNames[i] << endl;
00882 }
00883 }
00884
00885
00886 kmkernel->imapFolderMgr()->quiet( false );
00887 emit directoryListingFinished( this );
00888 account()->listDirProgressItem()->setComplete();
00889 }
00890
00891
00892 void KMFolderImap::initInbox()
00893 {
00894 KMFolderImap *f = 0;
00895 KMFolderNode *node = 0;
00896
00897 for (node = folder()->child()->first(); node;
00898 node = folder()->child()->next()) {
00899 if (!node->isDir() && node->name() == "INBOX") break;
00900 }
00901 if (node) {
00902 f = static_cast<KMFolderImap*>(static_cast<KMFolder*>(node)->storage());
00903 } else {
00904 f = static_cast<KMFolderImap*>
00905 (folder()->child()->createFolder("INBOX", true)->storage());
00906 if ( f )
00907 {
00908 f->folder()->setLabel( i18n("inbox") );
00909 f->close( "kmfolderimap" );
00910 }
00911 kmkernel->imapFolderMgr()->contentsChanged();
00912 }
00913 if ( f ) {
00914 f->initializeFrom( this, "/INBOX/", "message/directory" );
00915 f->setChildrenState( QString::null );
00916 }
00917
00918 account()->setHasInbox( true );
00919 }
00920
00921
00922 KMFolderImap* KMFolderImap::findParent( const QString& path, const QString& name )
00923 {
00924 QString parent = path.left( path.length() - name.length() - 2 );
00925 if ( parent.length() > 1 )
00926 {
00927
00928 parent = parent.right( parent.length() - 1 );
00929 if ( parent != label() )
00930 {
00931 KMFolderNode *node = folder()->child()->first();
00932
00933 while ( node )
00934 {
00935 if ( node->name() == parent )
00936 {
00937 KMFolder* fld = static_cast<KMFolder*>(node);
00938 KMFolderImap* imapFld = static_cast<KMFolderImap*>( fld->storage() );
00939 return imapFld;
00940 }
00941 node = folder()->child()->next();
00942 }
00943 }
00944 }
00945 return 0;
00946 }
00947
00948
00949 void KMFolderImap::checkFolders( const QStringList& subfolderNames,
00950 const QString& myNamespace )
00951 {
00952 QPtrList<KMFolder> toRemove;
00953 KMFolderNode *node = folder()->child()->first();
00954 while ( node )
00955 {
00956 if ( !node->isDir() && subfolderNames.findIndex(node->name()) == -1 )
00957 {
00958 KMFolder* fld = static_cast<KMFolder*>(node);
00959 KMFolderImap* imapFld = static_cast<KMFolderImap*>( fld->storage() );
00960
00961
00962 bool isInNamespace = ( myNamespace.isEmpty() ||
00963 myNamespace == account()->namespaceForFolder( imapFld ) );
00964 kdDebug(5006) << node->name() << " in namespace " << myNamespace << ":" <<
00965 isInNamespace << endl;
00966
00967 QString name = node->name();
00968 bool ignore = ( ( this == account()->rootFolder() ) &&
00969 ( imapFld->imapPath() == "/INBOX/" ||
00970 account()->isNamespaceFolder( name ) ||
00971 !isInNamespace ) );
00972
00973 if ( imapFld->imapPath().isEmpty() ) {
00974 ignore = false;
00975 }
00976 if ( !ignore )
00977 {
00978
00979 kdDebug(5006) << "checkFolders - " << node->name() << " disappeared" << endl;
00980 imapFld->setAlreadyRemoved( true );
00981 toRemove.append( fld );
00982 } else {
00983 kdDebug(5006) << "checkFolders - " << node->name() << " ignored" << endl;
00984 }
00985 }
00986 node = folder()->child()->next();
00987 }
00988
00989 for ( KMFolder* doomed=toRemove.first(); doomed; doomed = toRemove.next() )
00990 kmkernel->imapFolderMgr()->remove( doomed );
00991 }
00992
00993
00994 void KMFolderImap::initializeFrom( KMFolderImap* parent, QString folderPath,
00995 QString mimeType )
00996 {
00997 setAccount( parent->account() );
00998 setImapPath( folderPath );
00999 setNoContent( mimeType == "inode/directory" );
01000 setNoChildren( mimeType == "message/digest" );
01001 }
01002
01003
01004 void KMFolderImap::setChildrenState( QString 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(), SIGNAL( connectionResult(int, const QString&) ),
01038 this, 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(), SIGNAL( connectionResult(int, const QString&) ),
01052 this, 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 QStyleSheet::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, SIGNAL(result(KIO::Job *)),
01083 SLOT(slotCheckValidityResult(KIO::Job *)));
01084 connect(job, SIGNAL(data(KIO::Job *, const QByteArray &)),
01085 SLOT(slotSimpleData(KIO::Job *, const QByteArray &)));
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 QCString cstr((*it).data.data(), (*it).data.size() + 1);
01126 int a = cstr.find("X-uidValidity: ");
01127 int b = cstr.find("\r\n", a);
01128 QString 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 QString 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 QString 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 = QString::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 QString &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, SIGNAL(result(KIO::Job *)),
01242 this, SLOT(slotListFolderResult(KIO::Job *)));
01243 connect(job, SIGNAL(entries(KIO::Job *, const KIO::UDSEntryList &)),
01244 this, 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, SIGNAL(result(KIO::Job *)),
01258 this, SLOT(slotGetLastMessagesResult(KIO::Job *)));
01259 connect(newJob, SIGNAL(data(KIO::Job *, const QByteArray &)),
01260 this, SLOT(slotGetMessagesData(KIO::Job *, const QByteArray &)));
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 QString 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 QStringList::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( QString::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 QStringList 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 (QStringList::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, SIGNAL(result(KIO::Job *)),
01364 this, (i == sets.at(sets.count() - 1))
01365 ? SLOT(slotGetLastMessagesResult(KIO::Job *))
01366 : SLOT(slotGetMessagesResult(KIO::Job *)));
01367 connect(newJob, SIGNAL(data(KIO::Job *, const QByteArray &)),
01368 this, SLOT(slotGetMessagesData(KIO::Job *, const QByteArray &)));
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 QString 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 + "," + QString::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 QString KMFolderImap::statusToFlags(KMMsgStatus status, int supportedFlags)
01482 {
01483 QString 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 QByteArray & data)
01523 {
01524 if ( data.isEmpty() ) return;
01525 ImapAccountBase::JobIterator it = account()->findJob(job);
01526 if ( it == account()->jobsEnd() ) return;
01527 (*it).cdata += QCString(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( QString::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 QString 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, QString 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 = QString::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( QPtrList<KMMessage>& msgList, const QString& 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 QString &name, const QString& 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 QString parent = ( parentPath.isEmpty() ? imapPath() : parentPath );
01732 QString 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, SIGNAL(result(KIO::Job *)),
01744 this, 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 QString 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 QTextCodec *sUtf7Codec = 0;
01776
01777 QTextCodec * KMFolderImap::utf7Codec()
01778 {
01779 if (!sUtf7Codec) sUtf7Codec = QTextCodec::codecForName("utf-7");
01780 return sUtf7Codec;
01781 }
01782
01783
01784
01785 QString KMFolderImap::encodeFileName(const QString &name)
01786 {
01787 QString result = utf7Codec()->fromUnicode(name);
01788 return KURL::encode_string_no_slash(result);
01789 }
01790
01791
01792
01793 QString KMFolderImap::decodeFileName(const QString &name)
01794 {
01795 QString 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 QByteArray & data)
01811 {
01812 if ( data.isEmpty() ) return;
01813 ImapAccountBase::JobIterator it = account()->findJob(job);
01814 if ( it == account()->jobsEnd() ) return;
01815 QBuffer 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=" + QString::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, SIGNAL(result(KIO::Job *)),
01845 account(), SLOT(slotSimpleResult(KIO::Job *)));
01846 }
01847
01848 void KMFolderImap::deleteMessage(const QPtrList<KMMessage>& msgList)
01849 {
01850 QPtrListIterator<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 QValueList<ulong> uids;
01859 getUids(msgList, uids);
01860 QStringList sets = makeSets(uids);
01861
01862 KURL url = account()->getUrl();
01863 KMFolderImap *msg_parent = static_cast<KMFolderImap*>(msgList.getFirst()->storage());
01864 for ( QStringList::Iterator it = sets.begin(); it != sets.end(); ++it )
01865 {
01866 QString 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, SIGNAL(result(KIO::Job *)),
01878 account(), SLOT(slotSimpleResult(KIO::Job *)));
01879 }
01880 }
01881
01882
01883 void KMFolderImap::setStatus(int idx, KMMsgStatus status, bool toggle)
01884 {
01885 QValueList<int> ids; ids.append(idx);
01886 setStatus(ids, status, toggle);
01887 }
01888
01889 void KMFolderImap::setStatus(QValueList<int>& _ids, KMMsgStatus status, bool toggle)
01890 {
01891 FolderStorage::setStatus(_ids, status, toggle);
01892 QValueList<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 QValueList<ulong> seenUids, unseenUids;
01917 for ( QValueList<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 QStringList sets = KMFolderImap::makeSets( seenUids, true );
01930 for( QStringList::Iterator it = sets.begin(); it != sets.end(); ++it ) {
01931 QString imappath = imapPath() + ";UID=" + ( *it );
01932 account()->setImapSeenStatus( folder(), imappath, true );
01933 }
01934 }
01935 if ( !unseenUids.isEmpty() ) {
01936 QStringList sets = KMFolderImap::makeSets( unseenUids, true );
01937 for( QStringList::Iterator it = sets.begin(); it != sets.end(); ++it ) {
01938 QString imappath = imapPath() + ";UID=" + ( *it );
01939 account()->setImapSeenStatus( folder(), imappath, false );
01940 }
01941 }
01942 return;
01943 }
01944
01945 QMap< QString, QStringList > groups;
01946 for ( QValueList<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 QString flags = statusToFlags(msg->status(), mPermanentFlags);
01952
01953 groups[flags].append(QString::number(msg->UID()));
01954 if (unget) unGetMsg(*it);
01955 }
01956 QMapIterator< QString, QStringList > dit;
01957 for ( dit = groups.begin(); dit != groups.end(); ++dit ) {
01958 QCString flags = dit.key().latin1();
01959 QStringList sets = makeSets( (*dit), true );
01960
01961 for ( QStringList::Iterator slit = sets.begin(); slit != sets.end(); ++slit ) {
01962 QString 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, SLOT(slotListFolderResult(KIO::Job *)));
01972 quiet( false );
01973 reallyGetFolder( QString::null );
01974 }
01975 }
01976
01977
01978 QStringList KMFolderImap::makeSets(const QStringList& uids, bool sort)
01979 {
01980 QValueList<ulong> tmp;
01981 for ( QStringList::ConstIterator it = uids.begin(); it != uids.end(); ++it )
01982 tmp.append( (*it).toInt() );
01983 return makeSets(tmp, sort);
01984 }
01985
01986 QStringList KMFolderImap::makeSets( QValueList<ulong>& uids, bool sort )
01987 {
01988 QStringList sets;
01989 QString set;
01990
01991 if (uids.size() == 1)
01992 {
01993 sets.append(QString::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 ( QValueList<ulong>::Iterator it = uids.begin(); it != uids.end(); ++it )
02004 {
02005 if (it == uids.begin() || set.isEmpty()) {
02006 set = QString::number(*it);
02007 inserted = true;
02008 } else
02009 {
02010 if (last+1 != *it)
02011 {
02012
02013 if (inserted)
02014 set += ',' + QString::number(*it);
02015 else
02016 set += ':' + QString::number(last) + ',' + QString::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 += ':' + QString::number(uids.last());
02033
02034 if (!set.isEmpty()) sets.append(set);
02035
02036 return sets;
02037 }
02038
02039
02040 void KMFolderImap::getUids(QValueList<int>& ids, QValueList<ulong>& uids)
02041 {
02042 KMMsgBase *msg = 0;
02043
02044 for ( QValueList<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 QPtrList<KMMessage>& msgList, QValueList<ulong>& uids)
02053 {
02054 KMMessage *msg = 0;
02055
02056 QPtrListIterator<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, SIGNAL(result(KIO::Job *)),
02079 account(), SLOT(slotSimpleResult(KIO::Job *)));
02080 }
02081
02082
02083 void KMFolderImap::slotProcessNewMail( int errorCode, const QString &errorMsg )
02084 {
02085 Q_UNUSED( errorMsg );
02086 disconnect( account(), SIGNAL( connectionResult(int, const QString&) ),
02087 this, SLOT( slotProcessNewMail(int, const QString&) ) );
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(), SIGNAL( connectionResult(int, const QString&) ),
02118 this, SLOT( slotProcessNewMail(int, const QString&) ) );
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 QStyleSheet::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, SIGNAL(result(KIO::Job *)),
02141 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 QValueList<ulong> KMFolderImap::splitSets(const QString uids)
02184 {
02185 QValueList<ulong> uidlist;
02186
02187
02188 QString buffer = QString::null;
02189 int setstart = -1;
02190
02191 for (uint i = 0; i < uids.length(); i++)
02192 {
02193 QChar 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() == QChar::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, SIGNAL(result(KIO::Job *)),
02251 account(), 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 )
02266 {
02267 mUserRights = userRights;
02268 kdDebug(5006) << imapPath() << " setUserRights: " << userRights << endl;
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 QPtrListIterator<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 QPtrListIterator<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 QString& errorMsg )
02329 {
02330 Q_UNUSED( errorMsg );
02331 disconnect( account(), SIGNAL( connectionResult( int, const QString& ) ),
02332 this, SLOT( slotCreatePendingFolders( int, const QString& ) ) );
02333 if ( !errorCode ) {
02334 QStringList::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 QValueList<Q_UINT32> serNums;
02349 emit searchResult( folder(), serNums, pattern, true );
02350 return;
02351 }
02352 SearchJob* job = new SearchJob( this, account(), pattern );
02353 connect( job, SIGNAL( searchDone( QValueList<Q_UINT32>, const KMSearchPattern*, bool ) ),
02354 this, SLOT( slotSearchDone( QValueList<Q_UINT32>, const KMSearchPattern*, bool ) ) );
02355 job->start();
02356 }
02357
02358
02359 void KMFolderImap::slotSearchDone( QValueList<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, SIGNAL( searchDone( Q_UINT32, const KMSearchPattern*, bool ) ),
02377 this, 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 QString& 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 ( mUserRights > 0 && !(mUserRights & KMail::ACLJobs::Delete) )
02440 return false;
02441 return true;
02442 }
02443
02444 #include "kmfolderimap.moc"