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