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