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