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