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