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 void KMFolderImap::setChildrenState( QString attributes )
00997 {
00998
00999 if ( attributes.find( "haschildren", 0, false ) != -1 )
01000 {
01001 setHasChildren( FolderStorage::HasChildren );
01002 } else if ( attributes.find( "hasnochildren", 0, false ) != -1 ||
01003 attributes.find( "noinferiors", 0, false ) != -1 )
01004 {
01005 setHasChildren( FolderStorage::HasNoChildren );
01006 } else
01007 {
01008 if ( account()->listOnlyOpenFolders() ) {
01009 setHasChildren( FolderStorage::HasChildren );
01010 } else {
01011 setHasChildren( FolderStorage::ChildrenUnknown );
01012 }
01013 }
01014 }
01015
01016
01017 void KMFolderImap::checkValidity()
01018 {
01019 if (!account()) {
01020 emit folderComplete(this, false);
01021 close("checkvalidity");
01022 return;
01023 }
01024 KURL url = account()->getUrl();
01025 url.setPath(imapPath() + ";UID=0:0");
01026 kdDebug(5006) << "KMFolderImap::checkValidity of: " << imapPath() << endl;
01027
01028
01029 disconnect( account(), SIGNAL( connectionResult(int, const QString&) ),
01030 this, SLOT( checkValidity() ) );
01031
01032 KMAcctImap::ConnectionState connectionState = account()->makeConnection();
01033 if ( connectionState == ImapAccountBase::Error ) {
01034 kdDebug(5006) << "KMFolderImap::checkValidity - got no connection" << endl;
01035 emit folderComplete(this, false);
01036 mContentState = imapNoInformation;
01037 close("checkvalidity");
01038 return;
01039 } else if ( connectionState == ImapAccountBase::Connecting ) {
01040
01041
01042 kdDebug(5006) << "CheckValidity - waiting for connection" << endl;
01043 connect( account(), SIGNAL( connectionResult(int, const QString&) ),
01044 this, SLOT( checkValidity() ) );
01045 return;
01046 }
01047
01048 if (mCheckingValidity) {
01049 kdDebug(5006) << "KMFolderImap::checkValidity - already checking" << endl;
01050 close("checkvalidity");
01051 return;
01052 }
01053
01054 if ( !mMailCheckProgressItem ) {
01055 ProgressItem* parent = ( account()->checkingSingleFolder() ? 0 :
01056 account()->mailCheckProgressItem() );
01057 mMailCheckProgressItem = ProgressManager::createProgressItem(
01058 parent,
01059 "MailCheck" + folder()->prettyURL(),
01060 QStyleSheet::escape( folder()->prettyURL() ),
01061 i18n("checking"),
01062 false,
01063 account()->useSSL() || account()->useTLS() );
01064 } else {
01065 mMailCheckProgressItem->setProgress(0);
01066 }
01067 if ( account()->mailCheckProgressItem() ) {
01068 account()->mailCheckProgressItem()->setStatus( folder()->prettyURL() );
01069 }
01070 ImapAccountBase::jobData jd( url.url() );
01071 KIO::SimpleJob *job = KIO::get(url, false, false);
01072 KIO::Scheduler::assignJobToSlave(account()->slave(), job);
01073 account()->insertJob(job, jd);
01074 connect(job, SIGNAL(result(KIO::Job *)),
01075 SLOT(slotCheckValidityResult(KIO::Job *)));
01076 connect(job, SIGNAL(data(KIO::Job *, const QByteArray &)),
01077 SLOT(slotSimpleData(KIO::Job *, const QByteArray &)));
01078
01079 mCheckingValidity = true;
01080 }
01081
01082
01083
01084 ulong KMFolderImap::lastUid()
01085 {
01086 if ( mLastUid > 0 )
01087 return mLastUid;
01088 open("lastuid");
01089 if (count() > 0)
01090 {
01091 KMMsgBase * base = getMsgBase(count()-1);
01092 mLastUid = base->UID();
01093 }
01094 close("lastuid");
01095 return mLastUid;
01096 }
01097
01098
01099
01100 void KMFolderImap::slotCheckValidityResult(KIO::Job * job)
01101 {
01102 kdDebug(5006) << "KMFolderImap::slotCheckValidityResult of: " << fileName() << endl;
01103 mCheckingValidity = false;
01104 ImapAccountBase::JobIterator it = account()->findJob(job);
01105 if ( it == account()->jobsEnd() ) return;
01106 if (job->error()) {
01107 if ( job->error() != KIO::ERR_ACCESS_DENIED ) {
01108
01109
01110
01111 account()->handleJobError( job, i18n("Error while querying the server status.") );
01112 }
01113 mContentState = imapNoInformation;
01114 emit folderComplete(this, false);
01115 close("checkvalidity");
01116 } else {
01117 QCString cstr((*it).data.data(), (*it).data.size() + 1);
01118 int a = cstr.find("X-uidValidity: ");
01119 int b = cstr.find("\r\n", a);
01120 QString uidv;
01121 if ( (b - a - 15) >= 0 )
01122 uidv = cstr.mid(a + 15, b - a - 15);
01123 a = cstr.find("X-Access: ");
01124 b = cstr.find("\r\n", a);
01125 QString access;
01126 if ( (b - a - 10) >= 0 )
01127 access = cstr.mid(a + 10, b - a - 10);
01128 mReadOnly = access == "Read only";
01129 a = cstr.find("X-Count: ");
01130 b = cstr.find("\r\n", a);
01131 int exists = -1;
01132 bool ok = false;
01133 if ( (b - a - 9) >= 0 )
01134 exists = cstr.mid(a + 9, b - a - 9).toInt(&ok);
01135 if ( !ok ) exists = -1;
01136 a = cstr.find( "X-PermanentFlags: " );
01137 b = cstr.find( "\r\n", a );
01138 if ( a >= 0 && (b - a - 18) >= 0 )
01139 mPermanentFlags = cstr.mid( a + 18, b - a - 18 ).toInt(&ok);
01140 if ( !ok ) mPermanentFlags = 0;
01141 QString startUid;
01142 if (uidValidity() != uidv)
01143 {
01144
01145 kdDebug(5006) << k_funcinfo << "uidValidty changed from "
01146 << uidValidity() << " to " << uidv << endl;
01147 if ( !uidValidity().isEmpty() )
01148 {
01149 account()->ignoreJobsForFolder( folder() );
01150 mUidMetaDataMap.clear();
01151 }
01152 mLastUid = 0;
01153 setUidValidity(uidv);
01154 writeConfig();
01155 } else {
01156 if (!mCheckFlags)
01157 startUid = QString::number(lastUid() + 1);
01158 }
01159 account()->removeJob(it);
01160 if ( mMailCheckProgressItem )
01161 {
01162 if ( startUid.isEmpty() ) {
01163
01164 mMailCheckProgressItem->setTotalItems( exists );
01165 } else {
01166
01167 int remain = exists - count();
01168 if ( remain < 0 ) remain = 1;
01169 mMailCheckProgressItem->setTotalItems( remain );
01170 }
01171 mMailCheckProgressItem->setCompletedItems( 0 );
01172 }
01173 reallyGetFolder(startUid);
01174 }
01175 }
01176
01177
01178 void KMFolderImap::getAndCheckFolder(bool force)
01179 {
01180 if (mNoContent)
01181 return getFolder(force);
01182
01183 if ( account() )
01184 account()->processNewMailInFolder( folder() );
01185 if (force) {
01186
01187 mCheckFlags = true;
01188 }
01189 }
01190
01191
01192 void KMFolderImap::getFolder(bool force)
01193 {
01194 mGuessedUnreadMsgs = -1;
01195 if (mNoContent)
01196 {
01197 mContentState = imapFinished;
01198 emit folderComplete(this, true);
01199 return;
01200 }
01201 open("getfolder");
01202 mContentState = imapListingInProgress;
01203 if (force) {
01204
01205 mCheckFlags = true;
01206 }
01207 checkValidity();
01208 }
01209
01210
01211
01212 void KMFolderImap::reallyGetFolder(const QString &startUid)
01213 {
01214 KURL url = account()->getUrl();
01215 if ( account()->makeConnection() != ImapAccountBase::Connected )
01216 {
01217 mContentState = imapNoInformation;
01218 emit folderComplete(this, false);
01219 close("listfolder");
01220 return;
01221 }
01222 quiet(true);
01223 if (startUid.isEmpty())
01224 {
01225 if ( mMailCheckProgressItem )
01226 mMailCheckProgressItem->setStatus( i18n("Retrieving message status") );
01227 url.setPath(imapPath() + ";SECTION=UID FLAGS");
01228 KIO::SimpleJob *job = KIO::listDir(url, false);
01229 KIO::Scheduler::assignJobToSlave(account()->slave(), job);
01230 ImapAccountBase::jobData jd( url.url(), folder() );
01231 jd.cancellable = true;
01232 account()->insertJob(job, jd);
01233 connect(job, SIGNAL(result(KIO::Job *)),
01234 this, SLOT(slotListFolderResult(KIO::Job *)));
01235 connect(job, SIGNAL(entries(KIO::Job *, const KIO::UDSEntryList &)),
01236 this, SLOT(slotListFolderEntries(KIO::Job *,
01237 const KIO::UDSEntryList &)));
01238 } else {
01239 mContentState = imapDownloadInProgress;
01240 if ( mMailCheckProgressItem )
01241 mMailCheckProgressItem->setStatus( i18n("Retrieving messages") );
01242 url.setPath(imapPath() + ";UID=" + startUid
01243 + ":*;SECTION=ENVELOPE");
01244 KIO::SimpleJob *newJob = KIO::get(url, false, false);
01245 KIO::Scheduler::assignJobToSlave(account()->slave(), newJob);
01246 ImapAccountBase::jobData jd( url.url(), folder() );
01247 jd.cancellable = true;
01248 account()->insertJob(newJob, jd);
01249 connect(newJob, SIGNAL(result(KIO::Job *)),
01250 this, SLOT(slotGetLastMessagesResult(KIO::Job *)));
01251 connect(newJob, SIGNAL(data(KIO::Job *, const QByteArray &)),
01252 this, SLOT(slotGetMessagesData(KIO::Job *, const QByteArray &)));
01253 }
01254 }
01255
01256
01257
01258 void KMFolderImap::slotListFolderResult(KIO::Job * job)
01259 {
01260 ImapAccountBase::JobIterator it = account()->findJob(job);
01261 if ( it == account()->jobsEnd() ) return;
01262 QString uids;
01263 if (job->error())
01264 {
01265 account()->handleJobError( job,
01266 i18n("Error while listing the contents of the folder %1.").arg( label() ) );
01267 account()->removeJob(it);
01268 finishMailCheck( "listfolder", imapNoInformation );
01269 return;
01270 }
01271 mCheckFlags = false;
01272 QStringList::Iterator uid;
01273
01274
01275
01276
01277
01278
01279
01280
01281
01282 if ( count() ) {
01283 int idx = 0, c, serverFlags;
01284 ulong mailUid, serverUid;
01285 uid = (*it).items.begin();
01286 while ( idx < count() && uid != (*it).items.end() ) {
01287 KMMsgBase *msgBase = getMsgBase( idx );
01288 mailUid = msgBase->UID();
01289
01290
01291 c = (*uid).find(",");
01292 serverUid = (*uid).left( c ).toLong();
01293 serverFlags = (*uid).mid( c+1 ).toInt();
01294 if ( mailUid < serverUid ) {
01295 removeMsg( idx, true );
01296 } else if ( mailUid == serverUid ) {
01297
01298
01299
01300 if ( !mReadOnly || !GlobalSettings::allowLocalFlags() ) {
01301 int supportedFlags = mUploadAllFlags ? 31 : mPermanentFlags;
01302 if ( mReadOnly )
01303 supportedFlags = INT_MAX;
01304 flagsToStatus( msgBase, serverFlags, false, supportedFlags );
01305 } else
01306 seenFlagToStatus( msgBase, serverFlags, false );
01307 idx++;
01308 uid = (*it).items.remove(uid);
01309 if ( msgBase->getMsgSerNum() > 0 ) {
01310 saveMsgMetaData( static_cast<KMMessage*>(msgBase) );
01311 }
01312 }
01313 else break;
01314 }
01315
01316
01317 while (idx < count()) removeMsg(idx, true);
01318 }
01319
01320 for (uid = (*it).items.begin(); uid != (*it).items.end(); ++uid)
01321 (*uid).truncate((*uid).find(","));
01322 ImapAccountBase::jobData jd( QString::null, (*it).parent );
01323 jd.total = (*it).items.count();
01324 if (jd.total == 0)
01325 {
01326 finishMailCheck( "listfolder", imapFinished );
01327 account()->removeJob(it);
01328 return;
01329 }
01330 if ( mMailCheckProgressItem )
01331 {
01332
01333 mMailCheckProgressItem->setCompletedItems( 0 );
01334 mMailCheckProgressItem->setTotalItems( jd.total );
01335 mMailCheckProgressItem->setProgress( 0 );
01336 mMailCheckProgressItem->setStatus( i18n("Retrieving messages") );
01337 }
01338
01339 QStringList sets;
01340 uid = (*it).items.begin();
01341 if (jd.total == 1) sets.append(*uid + ":" + *uid);
01342 else sets = makeSets( (*it).items );
01343 account()->removeJob(it);
01344
01345
01346 for (QStringList::Iterator i = sets.begin(); i != sets.end(); ++i)
01347 {
01348 mContentState = imapDownloadInProgress;
01349 KURL url = account()->getUrl();
01350 url.setPath(imapPath() + ";UID=" + *i + ";SECTION=ENVELOPE");
01351 KIO::SimpleJob *newJob = KIO::get(url, false, false);
01352 jd.url = url.url();
01353 KIO::Scheduler::assignJobToSlave(account()->slave(), newJob);
01354 account()->insertJob(newJob, jd);
01355 connect(newJob, SIGNAL(result(KIO::Job *)),
01356 this, (i == sets.at(sets.count() - 1))
01357 ? SLOT(slotGetLastMessagesResult(KIO::Job *))
01358 : SLOT(slotGetMessagesResult(KIO::Job *)));
01359 connect(newJob, SIGNAL(data(KIO::Job *, const QByteArray &)),
01360 this, SLOT(slotGetMessagesData(KIO::Job *, const QByteArray &)));
01361 }
01362 }
01363
01364
01365
01366 void KMFolderImap::slotListFolderEntries(KIO::Job * job,
01367 const KIO::UDSEntryList & uds)
01368 {
01369 ImapAccountBase::JobIterator it = account()->findJob(job);
01370 if ( it == account()->jobsEnd() ) return;
01371 QString mimeType, name;
01372 long int flags = 0;
01373 for (KIO::UDSEntryList::ConstIterator udsIt = uds.begin();
01374 udsIt != uds.end(); udsIt++)
01375 {
01376 for (KIO::UDSEntry::ConstIterator eIt = (*udsIt).begin();
01377 eIt != (*udsIt).end(); eIt++)
01378 {
01379 if ((*eIt).m_uds == KIO::UDS_NAME)
01380 name = (*eIt).m_str;
01381 else if ((*eIt).m_uds == KIO::UDS_MIME_TYPE)
01382 mimeType = (*eIt).m_str;
01383 else if ((*eIt).m_uds == KIO::UDS_ACCESS)
01384 flags = (*eIt).m_long;
01385 }
01386 if ((mimeType == "message/rfc822-imap" || mimeType == "message/rfc822") &&
01387 !(flags & 8)) {
01388 (*it).items.append(name + "," + QString::number(flags));
01389 if ( mMailCheckProgressItem ) {
01390 mMailCheckProgressItem->incCompletedItems();
01391 mMailCheckProgressItem->updateProgress();
01392 }
01393 }
01394 }
01395 }
01396
01397
01398
01399
01400
01401
01402
01403
01404
01405
01406
01407
01408
01409
01410
01411
01412
01413
01414
01415
01416 void KMFolderImap::flagsToStatus(KMMsgBase *msg, int flags, bool newMsg, int supportedFlags )
01417 {
01418 if ( !msg ) return;
01419
01420
01421 static const struct {
01422 const int imapFlag;
01423 const int kmFlag;
01424 const bool standardFlag;
01425 } imapFlagMap[] = {
01426 { 2, KMMsgStatusReplied, true },
01427 { 4, KMMsgStatusFlag, true },
01428 { 128, KMMsgStatusForwarded, false },
01429 { 256, KMMsgStatusTodo, false },
01430 { 512, KMMsgStatusWatched, false },
01431 { 1024, KMMsgStatusIgnored, false }
01432 };
01433 static const int numFlags = sizeof imapFlagMap / sizeof *imapFlagMap;
01434
01435 const KMMsgStatus oldStatus = msg->status();
01436 for ( int i = 0; i < numFlags; ++i ) {
01437 if ( ( (supportedFlags & imapFlagMap[i].imapFlag) == 0 && (supportedFlags & 64) == 0 )
01438 && !imapFlagMap[i].standardFlag ) {
01439 continue;
01440 }
01441 if ( ((flags & imapFlagMap[i].imapFlag) > 0) != ((oldStatus & imapFlagMap[i].kmFlag) > 0) ) {
01442 msg->toggleStatus( imapFlagMap[i].kmFlag );
01443 }
01444 }
01445
01446 seenFlagToStatus( msg, flags, newMsg );
01447 }
01448
01449 void KMFolderImap::seenFlagToStatus(KMMsgBase * msg, int flags, bool newMsg)
01450 {
01451 if ( !msg ) return;
01452
01453 const KMMsgStatus oldStatus = msg->status();
01454 if ( (flags & 1) && (oldStatus & KMMsgStatusOld) == 0 )
01455 msg->setStatus( KMMsgStatusOld );
01456
01457
01458
01459
01460 if ( msg->isOfUnknownStatus() || (!(flags&1) && !(oldStatus&(KMMsgStatusNew|KMMsgStatusUnread)) ) ) {
01461 if (newMsg) {
01462 if ( (oldStatus & KMMsgStatusNew) == 0 )
01463 msg->setStatus( KMMsgStatusNew );
01464 } else {
01465 if ( (oldStatus & KMMsgStatusUnread) == 0 )
01466 msg->setStatus( KMMsgStatusUnread );
01467 }
01468 }
01469 }
01470
01471
01472
01473 QString KMFolderImap::statusToFlags(KMMsgStatus status, int supportedFlags)
01474 {
01475 QString flags;
01476 if (status & KMMsgStatusDeleted)
01477 flags = "\\DELETED";
01478 else {
01479 if (status & KMMsgStatusOld || status & KMMsgStatusRead)
01480 flags = "\\SEEN ";
01481 if (status & KMMsgStatusReplied)
01482 flags += "\\ANSWERED ";
01483 if (status & KMMsgStatusFlag)
01484 flags += "\\FLAGGED ";
01485
01486 if ( (status & KMMsgStatusForwarded) && ((supportedFlags & 64) || (supportedFlags & 128)) )
01487 flags += "$FORWARDED ";
01488 if ( (status & KMMsgStatusTodo) && ((supportedFlags & 64) || (supportedFlags & 256)) )
01489 flags += "$TODO ";
01490 if ( (status & KMMsgStatusWatched) && ((supportedFlags & 64) || (supportedFlags & 512)) )
01491 flags += "$WATCHED ";
01492 if ( (status & KMMsgStatusIgnored) && ((supportedFlags & 64) || (supportedFlags & 1024)) )
01493 flags += "$IGNORED ";
01494 }
01495
01496 return flags.simplifyWhiteSpace();
01497 }
01498
01499
01500 void
01501 KMFolderImap::ignoreJobsForMessage( KMMessage* msg )
01502 {
01503 if ( !msg || msg->transferInProgress() ||
01504 !msg->parent() || msg->parent()->folderType() != KMFolderTypeImap )
01505 return;
01506 KMAcctImap *account;
01507 if ( !(account = static_cast<KMFolderImap*>(msg->storage())->account()) )
01508 return;
01509
01510 account->ignoreJobsForMessage( msg );
01511 }
01512
01513
01514 void KMFolderImap::slotGetMessagesData(KIO::Job * job, const QByteArray & data)
01515 {
01516 if ( data.isEmpty() ) return;
01517 ImapAccountBase::JobIterator it = account()->findJob(job);
01518 if ( it == account()->jobsEnd() ) return;
01519 (*it).cdata += QCString(data, data.size() + 1);
01520 int pos = (*it).cdata.find("\r\n--IMAPDIGEST");
01521 if ( pos == -1 ) {
01522
01523
01524 return;
01525 }
01526 if (pos > 0)
01527 {
01528 int p = (*it).cdata.find("\r\nX-uidValidity:");
01529 if (p != -1) setUidValidity((*it).cdata
01530 .mid(p + 17, (*it).cdata.find("\r\n", p+1) - p - 17));
01531 int c = (*it).cdata.find("\r\nX-Count:");
01532 if ( c != -1 )
01533 {
01534 bool ok;
01535 int exists = (*it).cdata.mid( c+10,
01536 (*it).cdata.find("\r\n", c+1) - c-10 ).toInt(&ok);
01537 if ( ok && exists < count() ) {
01538 kdDebug(5006) << "KMFolderImap::slotGetMessagesData - server has less messages (" <<
01539 exists << ") then folder (" << count() << "), so reload" << endl;
01540 open("getMessage");
01541 reallyGetFolder( QString::null );
01542 (*it).cdata.remove(0, pos);
01543 return;
01544 } else if ( ok ) {
01545 int delta = exists - count();
01546 if ( mMailCheckProgressItem ) {
01547 mMailCheckProgressItem->setTotalItems( delta );
01548 }
01549 }
01550 }
01551 (*it).cdata.remove(0, pos);
01552 }
01553 pos = (*it).cdata.find("\r\n--IMAPDIGEST", 1);
01554 int flags;
01555 while (pos >= 0)
01556 {
01557 KMMessage *msg = new KMMessage;
01558 msg->setComplete( false );
01559 msg->setReadyToShow( false );
01560
01561 if ( pos != 14 ) {
01562 msg->fromString( (*it).cdata.mid(16, pos - 16) );
01563 flags = msg->headerField("X-Flags").toInt();
01564 ulong uid = msg->UID();
01565 KMMsgMetaData *md = 0;
01566 if ( mUidMetaDataMap.find( uid ) ) {
01567 md = mUidMetaDataMap[uid];
01568 }
01569 ulong serNum = 0;
01570 if ( md ) {
01571 serNum = md->serNum();
01572 }
01573 bool ok = true;
01574 if ( uid <= lastUid() && serNum > 0 ) {
01575
01576 ok = false;
01577 }
01578
01579 if ( flags & 8 )
01580 ok = false;
01581 if ( !ok ) {
01582 delete msg;
01583 msg = 0;
01584 } else {
01585 if ( serNum > 0 ) {
01586
01587 msg->setMsgSerNum( serNum );
01588 }
01589
01590 if ( md ) {
01591 msg->setStatus( md->status() );
01592 } else if ( !account()->hasCapability("uidplus") ) {
01593
01594
01595 QString id = msg->msgIdMD5();
01596 if ( mMetaDataMap.find( id ) ) {
01597 md = mMetaDataMap[id];
01598 msg->setStatus( md->status() );
01599 if ( md->serNum() != 0 && serNum == 0 ) {
01600 msg->setMsgSerNum( md->serNum() );
01601 }
01602 mMetaDataMap.remove( id );
01603 delete md;
01604 }
01605 }
01606 KMFolderMbox::addMsg(msg, 0);
01607
01608 flagsToStatus((KMMsgBase*)msg, flags, true, mUploadAllFlags ? 31 : mPermanentFlags);
01609
01610 msg->setMsgSizeServer( msg->headerField("X-Length").toUInt() );
01611 msg->setUID(uid);
01612 if ( msg->getMsgSerNum() > 0 ) {
01613 saveMsgMetaData( msg );
01614 }
01615
01616 if ( folder()->isSystemFolder() && imapPath() == "/INBOX/"
01617 && kmkernel->filterMgr()->atLeastOneIncomingFilterAppliesTo( account()->id() ) )
01618 account()->execFilters( msg->getMsgSerNum() );
01619
01620 if ( count() > 1 ) {
01621 unGetMsg(count() - 1);
01622 }
01623 mLastUid = uid;
01624 if ( mMailCheckProgressItem ) {
01625 mMailCheckProgressItem->incCompletedItems();
01626 mMailCheckProgressItem->updateProgress();
01627 }
01628 }
01629 }
01630 (*it).cdata.remove(0, pos);
01631 (*it).done++;
01632 pos = (*it).cdata.find("\r\n--IMAPDIGEST", 1);
01633 }
01634 }
01635
01636
01637 FolderJob*
01638 KMFolderImap::doCreateJob( KMMessage *msg, FolderJob::JobType jt,
01639 KMFolder *folder, QString partSpecifier,
01640 const AttachmentStrategy *as ) const
01641 {
01642 KMFolderImap* kmfi = folder? dynamic_cast<KMFolderImap*>(folder->storage()) : 0;
01643 if ( jt == FolderJob::tGetMessage && partSpecifier == "STRUCTURE" &&
01644 account() && account()->loadOnDemand() &&
01645 ( msg->msgSizeServer() > 5000 || msg->msgSizeServer() == 0 ) &&
01646 ( msg->signatureState() == KMMsgNotSigned ||
01647 msg->signatureState() == KMMsgSignatureStateUnknown ) &&
01648 ( msg->encryptionState() == KMMsgNotEncrypted ||
01649 msg->encryptionState() == KMMsgEncryptionStateUnknown ) )
01650 {
01651
01652
01653 ImapJob *job = new ImapJob( msg, jt, kmfi, "HEADER" );
01654 job->start();
01655 ImapJob *job2 = new ImapJob( msg, jt, kmfi, "STRUCTURE", as );
01656 job2->start();
01657 job->setParentFolder( this );
01658 return job;
01659 } else {
01660
01661 if ( partSpecifier == "STRUCTURE" )
01662 partSpecifier = QString::null;
01663
01664 ImapJob *job = new ImapJob( msg, jt, kmfi, partSpecifier );
01665 job->setParentFolder( this );
01666 return job;
01667 }
01668 }
01669
01670
01671 FolderJob*
01672 KMFolderImap::doCreateJob( QPtrList<KMMessage>& msgList, const QString& sets,
01673 FolderJob::JobType jt, KMFolder *folder ) const
01674 {
01675 KMFolderImap* kmfi = dynamic_cast<KMFolderImap*>(folder->storage());
01676 ImapJob *job = new ImapJob( msgList, sets, jt, kmfi );
01677 job->setParentFolder( this );
01678 return job;
01679 }
01680
01681
01682 void KMFolderImap::getMessagesResult(KIO::Job * job, bool lastSet)
01683 {
01684 ImapAccountBase::JobIterator it = account()->findJob(job);
01685 if ( it == account()->jobsEnd() ) return;
01686 if (job->error()) {
01687 account()->handleJobError( job, i18n("Error while retrieving messages.") );
01688 finishMailCheck( "getMessage", imapNoInformation );
01689 return;
01690 }
01691 if (lastSet) {
01692 finishMailCheck( "getMessage", imapFinished );
01693 account()->removeJob(it);
01694 }
01695 }
01696
01697
01698
01699 void KMFolderImap::slotGetLastMessagesResult(KIO::Job * job)
01700 {
01701 getMessagesResult(job, true);
01702 }
01703
01704
01705
01706 void KMFolderImap::slotGetMessagesResult(KIO::Job * job)
01707 {
01708 getMessagesResult(job, false);
01709 }
01710
01711
01712
01713 void KMFolderImap::createFolder(const QString &name, const QString& parentPath,
01714 bool askUser)
01715 {
01716 kdDebug(5006) << "KMFolderImap::createFolder - name=" << name << ",parent=" <<
01717 parentPath << ",askUser=" << askUser << endl;
01718 if ( account()->makeConnection() != ImapAccountBase::Connected ) {
01719 kdWarning(5006) << "KMFolderImap::createFolder - got no connection" << endl;
01720 return;
01721 }
01722 KURL url = account()->getUrl();
01723 QString parent = ( parentPath.isEmpty() ? imapPath() : parentPath );
01724 QString path = account()->createImapPath( parent, name );
01725 if ( askUser ) {
01726 path += "/;INFO=ASKUSER";
01727 }
01728 url.setPath( path );
01729
01730 KIO::SimpleJob *job = KIO::mkdir(url);
01731 KIO::Scheduler::assignJobToSlave(account()->slave(), job);
01732 ImapAccountBase::jobData jd( url.url(), folder() );
01733 jd.items = name;
01734 account()->insertJob(job, jd);
01735 connect(job, SIGNAL(result(KIO::Job *)),
01736 this, SLOT(slotCreateFolderResult(KIO::Job *)));
01737 }
01738
01739
01740
01741 void KMFolderImap::slotCreateFolderResult(KIO::Job * job)
01742 {
01743 ImapAccountBase::JobIterator it = account()->findJob(job);
01744 if ( it == account()->jobsEnd() ) return;
01745
01746 QString name;
01747 if ( it.data().items.count() > 0 )
01748 name = it.data().items.first();
01749
01750 if (job->error())
01751 {
01752 if ( job->error() == KIO::ERR_COULD_NOT_MKDIR ) {
01753
01754 account()->listDirectory( );
01755 }
01756 account()->handleJobError( job, i18n("Error while creating a folder.") );
01757 emit folderCreationResult( name, false );
01758 } else {
01759 listDirectory();
01760 account()->removeJob(job);
01761 emit folderCreationResult( name, true );
01762 }
01763 }
01764
01765
01766
01767 static QTextCodec *sUtf7Codec = 0;
01768
01769 QTextCodec * KMFolderImap::utf7Codec()
01770 {
01771 if (!sUtf7Codec) sUtf7Codec = QTextCodec::codecForName("utf-7");
01772 return sUtf7Codec;
01773 }
01774
01775
01776
01777 QString KMFolderImap::encodeFileName(const QString &name)
01778 {
01779 QString result = utf7Codec()->fromUnicode(name);
01780 return KURL::encode_string_no_slash(result);
01781 }
01782
01783
01784
01785 QString KMFolderImap::decodeFileName(const QString &name)
01786 {
01787 QString result = KURL::decode_string(name);
01788 return utf7Codec()->toUnicode(result.latin1());
01789 }
01790
01791
01792 bool KMFolderImap::autoExpunge()
01793 {
01794 if (account())
01795 return account()->autoExpunge();
01796
01797 return false;
01798 }
01799
01800
01801
01802 void KMFolderImap::slotSimpleData(KIO::Job * job, const QByteArray & data)
01803 {
01804 if ( data.isEmpty() ) return;
01805 ImapAccountBase::JobIterator it = account()->findJob(job);
01806 if ( it == account()->jobsEnd() ) return;
01807 QBuffer buff((*it).data);
01808 buff.open(IO_WriteOnly | IO_Append);
01809 buff.writeBlock(data.data(), data.size());
01810 buff.close();
01811 }
01812
01813
01814 void KMFolderImap::deleteMessage(KMMessage * msg)
01815 {
01816 mUidMetaDataMap.remove( msg->UID() );
01817 mMetaDataMap.remove( msg->msgIdMD5() );
01818 KURL url = account()->getUrl();
01819 KMFolderImap *msg_parent = static_cast<KMFolderImap*>(msg->storage());
01820 ulong uid = msg->UID();
01821
01822
01823
01824 if ( uid == 0 ) {
01825 kdDebug( 5006 ) << "KMFolderImap::deleteMessage: Attempt to delete "
01826 "an empty UID. Aborting." << endl;
01827 return;
01828 }
01829 url.setPath(msg_parent->imapPath() + ";UID=" + QString::number(uid) );
01830 if ( account()->makeConnection() != ImapAccountBase::Connected )
01831 return;
01832 KIO::SimpleJob *job = KIO::file_delete(url, false);
01833 KIO::Scheduler::assignJobToSlave(account()->slave(), job);
01834 ImapAccountBase::jobData jd( url.url(), 0 );
01835 account()->insertJob(job, jd);
01836 connect(job, SIGNAL(result(KIO::Job *)),
01837 account(), SLOT(slotSimpleResult(KIO::Job *)));
01838 }
01839
01840 void KMFolderImap::deleteMessage(const QPtrList<KMMessage>& msgList)
01841 {
01842 QPtrListIterator<KMMessage> it( msgList );
01843 KMMessage *msg;
01844 while ( (msg = it.current()) != 0 ) {
01845 ++it;
01846 mUidMetaDataMap.remove( msg->UID() );
01847 mMetaDataMap.remove( msg->msgIdMD5() );
01848 }
01849
01850 QValueList<ulong> uids;
01851 getUids(msgList, uids);
01852 QStringList sets = makeSets(uids);
01853
01854 KURL url = account()->getUrl();
01855 KMFolderImap *msg_parent = static_cast<KMFolderImap*>(msgList.getFirst()->storage());
01856 for ( QStringList::Iterator it = sets.begin(); it != sets.end(); ++it )
01857 {
01858 QString uid = *it;
01859
01860
01861 if ( uid.isEmpty() ) continue;
01862 url.setPath(msg_parent->imapPath() + ";UID=" + uid);
01863 if ( account()->makeConnection() != ImapAccountBase::Connected )
01864 return;
01865 KIO::SimpleJob *job = KIO::file_delete(url, false);
01866 KIO::Scheduler::assignJobToSlave(account()->slave(), job);
01867 ImapAccountBase::jobData jd( url.url(), 0 );
01868 account()->insertJob(job, jd);
01869 connect(job, SIGNAL(result(KIO::Job *)),
01870 account(), SLOT(slotSimpleResult(KIO::Job *)));
01871 }
01872 }
01873
01874
01875 void KMFolderImap::setStatus(int idx, KMMsgStatus status, bool toggle)
01876 {
01877 QValueList<int> ids; ids.append(idx);
01878 setStatus(ids, status, toggle);
01879 }
01880
01881 void KMFolderImap::setStatus(QValueList<int>& _ids, KMMsgStatus status, bool toggle)
01882 {
01883 FolderStorage::setStatus(_ids, status, toggle);
01884 QValueList<int> ids;
01885 if ( mUploadAllFlags ) {
01886 kdDebug(5006) << k_funcinfo << "Migrating all flags to the server" << endl;
01887 ids.clear();
01888 for ( int i = 0; i < count(); ++i )
01889 ids << i;
01890 mUploadAllFlags = false;
01891 } else {
01892 ids = _ids;
01893 }
01894
01895
01896
01897
01898
01899
01900
01901
01902
01903
01904
01905
01906 if ( mReadOnly ) {
01907
01908 QValueList<ulong> seenUids, unseenUids;
01909 for ( QValueList<int>::ConstIterator it = ids.constBegin(); it != ids.constEnd(); ++it ) {
01910 KMMessage *msg = 0;
01911 bool unget = !isMessage(*it);
01912 msg = getMsg(*it);
01913 if (!msg) continue;
01914 if ( msg->status() & KMMsgStatusOld || msg->status() & KMMsgStatusRead )
01915 seenUids.append( msg->UID() );
01916 else
01917 unseenUids.append( msg->UID() );
01918 if (unget) unGetMsg(*it);
01919 }
01920 if ( !seenUids.isEmpty() ) {
01921 QStringList sets = KMFolderImap::makeSets( seenUids, true );
01922 for( QStringList::Iterator it = sets.begin(); it != sets.end(); ++it ) {
01923 QString imappath = imapPath() + ";UID=" + ( *it );
01924 account()->setImapSeenStatus( folder(), imappath, true );
01925 }
01926 }
01927 if ( !unseenUids.isEmpty() ) {
01928 QStringList sets = KMFolderImap::makeSets( unseenUids, true );
01929 for( QStringList::Iterator it = sets.begin(); it != sets.end(); ++it ) {
01930 QString imappath = imapPath() + ";UID=" + ( *it );
01931 account()->setImapSeenStatus( folder(), imappath, false );
01932 }
01933 }
01934 return;
01935 }
01936
01937 QMap< QString, QStringList > groups;
01938 for ( QValueList<int>::Iterator it = ids.begin(); it != ids.end(); ++it ) {
01939 KMMessage *msg = 0;
01940 bool unget = !isMessage(*it);
01941 msg = getMsg(*it);
01942 if (!msg) continue;
01943 QString flags = statusToFlags(msg->status(), mPermanentFlags);
01944
01945 groups[flags].append(QString::number(msg->UID()));
01946 if (unget) unGetMsg(*it);
01947 }
01948 QMapIterator< QString, QStringList > dit;
01949 for ( dit = groups.begin(); dit != groups.end(); ++dit ) {
01950 QCString flags = dit.key().latin1();
01951 QStringList sets = makeSets( (*dit), true );
01952
01953 for ( QStringList::Iterator slit = sets.begin(); slit != sets.end(); ++slit ) {
01954 QString imappath = imapPath() + ";UID=" + ( *slit );
01955 account()->setImapStatus(folder(), imappath, flags);
01956 }
01957 }
01958 if ( mContentState == imapListingInProgress ) {
01959
01960
01961
01962 kdDebug(5006) << "Set status during folder listing, restarting listing." << endl;
01963 disconnect(this, SLOT(slotListFolderResult(KIO::Job *)));
01964 quiet( false );
01965 reallyGetFolder( QString::null );
01966 }
01967 }
01968
01969
01970 QStringList KMFolderImap::makeSets(const QStringList& uids, bool sort)
01971 {
01972 QValueList<ulong> tmp;
01973 for ( QStringList::ConstIterator it = uids.begin(); it != uids.end(); ++it )
01974 tmp.append( (*it).toInt() );
01975 return makeSets(tmp, sort);
01976 }
01977
01978 QStringList KMFolderImap::makeSets( QValueList<ulong>& uids, bool sort )
01979 {
01980 QStringList sets;
01981 QString set;
01982
01983 if (uids.size() == 1)
01984 {
01985 sets.append(QString::number(uids.first()));
01986 return sets;
01987 }
01988
01989 if (sort) qHeapSort(uids);
01990
01991 ulong last = 0;
01992
01993 bool inserted = false;
01994
01995 for ( QValueList<ulong>::Iterator it = uids.begin(); it != uids.end(); ++it )
01996 {
01997 if (it == uids.begin() || set.isEmpty()) {
01998 set = QString::number(*it);
01999 inserted = true;
02000 } else
02001 {
02002 if (last+1 != *it)
02003 {
02004
02005 if (inserted)
02006 set += ',' + QString::number(*it);
02007 else
02008 set += ':' + QString::number(last) + ',' + QString::number(*it);
02009 inserted = true;
02010 if (set.length() > 100)
02011 {
02012
02013 sets.append(set);
02014 set = "";
02015 }
02016 } else {
02017 inserted = false;
02018 }
02019 }
02020 last = *it;
02021 }
02022
02023 if (!inserted)
02024 set += ':' + QString::number(uids.last());
02025
02026 if (!set.isEmpty()) sets.append(set);
02027
02028 return sets;
02029 }
02030
02031
02032 void KMFolderImap::getUids(QValueList<int>& ids, QValueList<ulong>& uids)
02033 {
02034 KMMsgBase *msg = 0;
02035
02036 for ( QValueList<int>::Iterator it = ids.begin(); it != ids.end(); ++it )
02037 {
02038 msg = getMsgBase(*it);
02039 if (!msg) continue;
02040 uids.append(msg->UID());
02041 }
02042 }
02043
02044 void KMFolderImap::getUids(const QPtrList<KMMessage>& msgList, QValueList<ulong>& uids)
02045 {
02046 KMMessage *msg = 0;
02047
02048 QPtrListIterator<KMMessage> it( msgList );
02049 while ( (msg = it.current()) != 0 ) {
02050 ++it;
02051 if ( msg->UID() > 0 ) {
02052 uids.append( msg->UID() );
02053 }
02054 }
02055 }
02056
02057
02058 void KMFolderImap::expungeFolder(KMFolderImap * aFolder, bool quiet)
02059 {
02060 aFolder->setNeedsCompacting(false);
02061 KURL url = account()->getUrl();
02062 url.setPath(aFolder->imapPath() + ";UID=*");
02063 if ( account()->makeConnection() != ImapAccountBase::Connected )
02064 return;
02065 KIO::SimpleJob *job = KIO::file_delete(url, false);
02066 KIO::Scheduler::assignJobToSlave(account()->slave(), job);
02067 ImapAccountBase::jobData jd( url.url(), 0 );
02068 jd.quiet = quiet;
02069 account()->insertJob(job, jd);
02070 connect(job, SIGNAL(result(KIO::Job *)),
02071 account(), SLOT(slotSimpleResult(KIO::Job *)));
02072 }
02073
02074
02075 void KMFolderImap::slotProcessNewMail( int errorCode, const QString &errorMsg )
02076 {
02077 Q_UNUSED( errorMsg );
02078 disconnect( account(), SIGNAL( connectionResult(int, const QString&) ),
02079 this, SLOT( slotProcessNewMail(int, const QString&) ) );
02080 if ( !errorCode )
02081 processNewMail( false );
02082 else
02083 emit numUnreadMsgsChanged( folder() );
02084 }
02085
02086
02087 bool KMFolderImap::processNewMail(bool)
02088 {
02089
02090 if ( !account() ) {
02091 kdDebug(5006) << "KMFolderImap::processNewMail - account is null!" << endl;
02092 return false;
02093 }
02094 if ( imapPath().isEmpty() ) {
02095 kdDebug(5006) << "KMFolderImap::processNewMail - imapPath of " << name() << " is empty!" << endl;
02096
02097 setAlreadyRemoved( true );
02098 kmkernel->imapFolderMgr()->remove( folder() );
02099 return false;
02100 }
02101
02102 if ( account()->makeConnection() == ImapAccountBase::Error ) {
02103 kdDebug(5006) << "KMFolderImap::processNewMail - got no connection!" << endl;
02104 return false;
02105 } else if ( account()->makeConnection() == ImapAccountBase::Connecting )
02106 {
02107
02108 kdDebug(5006) << "KMFolderImap::processNewMail - waiting for connection: " << label() << endl;
02109 connect( account(), SIGNAL( connectionResult(int, const QString&) ),
02110 this, SLOT( slotProcessNewMail(int, const QString&) ) );
02111 return true;
02112 }
02113 KURL url = account()->getUrl();
02114 if (mReadOnly)
02115 url.setPath(imapPath() + ";SECTION=UIDNEXT");
02116 else
02117 url.setPath(imapPath() + ";SECTION=UNSEEN");
02118
02119 mMailCheckProgressItem = ProgressManager::createProgressItem(
02120 "MailCheckAccount" + account()->name(),
02121 "MailCheck" + folder()->prettyURL(),
02122 QStyleSheet::escape( folder()->prettyURL() ),
02123 i18n("updating message counts"),
02124 false,
02125 account()->useSSL() || account()->useTLS() );
02126
02127 KIO::SimpleJob *job = KIO::stat(url, false);
02128 KIO::Scheduler::assignJobToSlave(account()->slave(), job);
02129 ImapAccountBase::jobData jd(url.url(), folder() );
02130 jd.cancellable = true;
02131 account()->insertJob(job, jd);
02132 connect(job, SIGNAL(result(KIO::Job *)),
02133 SLOT(slotStatResult(KIO::Job *)));
02134 return true;
02135 }
02136
02137
02138
02139 void KMFolderImap::slotStatResult(KIO::Job * job)
02140 {
02141 slotCompleteMailCheckProgress();
02142 ImapAccountBase::JobIterator it = account()->findJob(job);
02143 if ( it == account()->jobsEnd() ) return;
02144 account()->removeJob(it);
02145 if (job->error())
02146 {
02147 account()->handleJobError( job, i18n("Error while getting folder information.") );
02148 } else {
02149 KIO::UDSEntry uds = static_cast<KIO::StatJob*>(job)->statResult();
02150 for (KIO::UDSEntry::ConstIterator it = uds.begin(); it != uds.end(); it++)
02151 {
02152 if ((*it).m_uds == KIO::UDS_SIZE)
02153 {
02154 if (mReadOnly)
02155 {
02156 mGuessedUnreadMsgs = -1;
02157 mGuessedUnreadMsgs = countUnread() + (*it).m_long - lastUid() - 1;
02158 if (mGuessedUnreadMsgs < 0) mGuessedUnreadMsgs = 0;
02159 } else {
02160 mGuessedUnreadMsgs = (*it).m_long;
02161 }
02162 }
02163 }
02164 }
02165 }
02166
02167
02168 int KMFolderImap::create()
02169 {
02170 readConfig();
02171 mUnreadMsgs = -1;
02172 return KMFolderMbox::create();
02173 }
02174
02175 QValueList<ulong> KMFolderImap::splitSets(const QString uids)
02176 {
02177 QValueList<ulong> uidlist;
02178
02179
02180 QString buffer = QString::null;
02181 int setstart = -1;
02182
02183 for (uint i = 0; i < uids.length(); i++)
02184 {
02185 QChar chr = uids[i];
02186 if (chr == ',')
02187 {
02188 if (setstart > -1)
02189 {
02190
02191 for (int j = setstart; j <= buffer.toInt(); j++)
02192 {
02193 uidlist.append(j);
02194 }
02195 setstart = -1;
02196 } else {
02197
02198 uidlist.append(buffer.toInt());
02199 }
02200 buffer = "";
02201 } else if (chr == ':') {
02202
02203 setstart = buffer.toInt();
02204 buffer = "";
02205 } else if (chr.category() == QChar::Number_DecimalDigit) {
02206
02207 buffer += chr;
02208 } else {
02209
02210 }
02211 }
02212
02213 if (setstart > -1)
02214 {
02215 for (int j = setstart; j <= buffer.toInt(); j++)
02216 {
02217 uidlist.append(j);
02218 }
02219 } else {
02220 uidlist.append(buffer.toInt());
02221 }
02222
02223 return uidlist;
02224 }
02225
02226
02227 int KMFolderImap::expungeContents()
02228 {
02229
02230 int rc = KMFolderMbox::expungeContents();
02231
02232
02233 KURL url = account()->getUrl();
02234 url.setPath( imapPath() + ";UID=1:*");
02235 if ( account()->makeConnection() == ImapAccountBase::Connected )
02236 {
02237 KIO::SimpleJob *job = KIO::file_delete(url, false);
02238 KIO::Scheduler::assignJobToSlave(account()->slave(), job);
02239 ImapAccountBase::jobData jd( url.url(), 0 );
02240 jd.quiet = true;
02241 account()->insertJob(job, jd);
02242 connect(job, SIGNAL(result(KIO::Job *)),
02243 account(), SLOT(slotSimpleResult(KIO::Job *)));
02244 }
02245
02246
02247
02248
02249 expungeFolder(this, true);
02250 getFolder();
02251
02252 return rc;
02253 }
02254
02255
02256 void
02257 KMFolderImap::setUserRights( unsigned int userRights )
02258 {
02259 mUserRights = userRights;
02260 kdDebug(5006) << imapPath() << " setUserRights: " << userRights << endl;
02261 }
02262
02263
02264 void KMFolderImap::slotCompleteMailCheckProgress()
02265 {
02266 if ( mMailCheckProgressItem ) {
02267 mMailCheckProgressItem->setComplete();
02268 mMailCheckProgressItem = 0;
02269 emit numUnreadMsgsChanged( folder() );
02270 }
02271 }
02272
02273
02274 void KMFolderImap::setSubfolderState( imapState state )
02275 {
02276 mSubfolderState = state;
02277 if ( state == imapNoInformation && folder()->child() )
02278 {
02279
02280 KMFolderNode* node;
02281 QPtrListIterator<KMFolderNode> it( *folder()->child() );
02282 for ( ; (node = it.current()); )
02283 {
02284 ++it;
02285 if (node->isDir()) continue;
02286 KMFolder *folder = static_cast<KMFolder*>(node);
02287 static_cast<KMFolderImap*>(folder->storage())->setSubfolderState( state );
02288 }
02289 }
02290 }
02291
02292
02293 void KMFolderImap::setIncludeInMailCheck( bool check )
02294 {
02295 bool changed = ( mCheckMail != check );
02296 mCheckMail = check;
02297 if ( changed )
02298 account()->slotUpdateFolderList();
02299 }
02300
02301
02302 void KMFolderImap::setAlreadyRemoved( bool removed )
02303 {
02304 mAlreadyRemoved = removed;
02305 if ( folder()->child() )
02306 {
02307
02308 KMFolderNode* node;
02309 QPtrListIterator<KMFolderNode> it( *folder()->child() );
02310 for ( ; (node = it.current()); )
02311 {
02312 ++it;
02313 if (node->isDir()) continue;
02314 KMFolder *folder = static_cast<KMFolder*>(node);
02315 static_cast<KMFolderImap*>(folder->storage())->setAlreadyRemoved( removed );
02316 }
02317 }
02318 }
02319
02320 void KMFolderImap::slotCreatePendingFolders( int errorCode, const QString& errorMsg )
02321 {
02322 Q_UNUSED( errorMsg );
02323 disconnect( account(), SIGNAL( connectionResult( int, const QString& ) ),
02324 this, SLOT( slotCreatePendingFolders( int, const QString& ) ) );
02325 if ( !errorCode ) {
02326 QStringList::Iterator it = mFoldersPendingCreation.begin();
02327 for ( ; it != mFoldersPendingCreation.end(); ++it ) {
02328 createFolder( *it );
02329 }
02330 }
02331 mFoldersPendingCreation.clear();
02332 }
02333
02334
02335 void KMFolderImap::search( const KMSearchPattern* pattern )
02336 {
02337 if ( !pattern || pattern->isEmpty() )
02338 {
02339
02340 QValueList<Q_UINT32> serNums;
02341 emit searchResult( folder(), serNums, pattern, true );
02342 return;
02343 }
02344 SearchJob* job = new SearchJob( this, account(), pattern );
02345 connect( job, SIGNAL( searchDone( QValueList<Q_UINT32>, const KMSearchPattern*, bool ) ),
02346 this, SLOT( slotSearchDone( QValueList<Q_UINT32>, const KMSearchPattern*, bool ) ) );
02347 job->start();
02348 }
02349
02350
02351 void KMFolderImap::slotSearchDone( QValueList<Q_UINT32> serNums,
02352 const KMSearchPattern* pattern,
02353 bool complete )
02354 {
02355 emit searchResult( folder(), serNums, pattern, complete );
02356 }
02357
02358
02359 void KMFolderImap::search( const KMSearchPattern* pattern, Q_UINT32 serNum )
02360 {
02361 if ( !pattern || pattern->isEmpty() )
02362 {
02363
02364 emit searchDone( folder(), serNum, pattern, false );
02365 return;
02366 }
02367 SearchJob* job = new SearchJob( this, account(), pattern, serNum );
02368 connect( job, SIGNAL( searchDone( Q_UINT32, const KMSearchPattern*, bool ) ),
02369 this, SLOT( slotSearchDone( Q_UINT32, const KMSearchPattern*, bool ) ) );
02370 job->start();
02371 }
02372
02373
02374 void KMFolderImap::slotSearchDone( Q_UINT32 serNum, const KMSearchPattern* pattern,
02375 bool matches )
02376 {
02377 emit searchDone( folder(), serNum, pattern, matches );
02378 }
02379
02380
02381 bool KMFolderImap::isMoveable() const
02382 {
02383 return ( hasChildren() == HasNoChildren &&
02384 !folder()->isSystemFolder() ) ? true : false;
02385 }
02386
02387
02388 ulong KMFolderImap::serNumForUID( ulong uid )
02389 {
02390 if ( mUidMetaDataMap.find( uid ) ) {
02391 KMMsgMetaData *md = mUidMetaDataMap[uid];
02392 return md->serNum();
02393 } else {
02394 kdDebug(5006) << "serNumForUID: unknown uid " << uid << endl;
02395 return 0;
02396 }
02397 }
02398
02399
02400 void KMFolderImap::saveMsgMetaData( KMMessage* msg, ulong uid )
02401 {
02402 if ( uid == 0 ) {
02403 uid = msg->UID();
02404 }
02405 ulong serNum = msg->getMsgSerNum();
02406 mUidMetaDataMap.replace( uid, new KMMsgMetaData(msg->status(), serNum) );
02407 }
02408
02409
02410 void KMFolderImap::setImapPath( const QString& path )
02411 {
02412 if ( path.isEmpty() ) {
02413 kdWarning(5006) << k_funcinfo << "ignoring empty path" << endl;
02414 } else {
02415 mImapPath = path;
02416 }
02417 }
02418
02419 void KMFolderImap::finishMailCheck( const char *dbg, imapState state )
02420 {
02421 quiet( false );
02422 mContentState = state;
02423 emit folderComplete( this, mContentState == imapFinished );
02424 close(dbg);
02425 }
02426
02427 bool KMFolderImap::canDeleteMessages() const
02428 {
02429 if ( isReadOnly() )
02430 return false;
02431 if ( mUserRights > 0 && !(mUserRights & KMail::ACLJobs::Delete) )
02432 return false;
02433 return true;
02434 }
02435
02436 #include "kmfolderimap.moc"