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