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