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