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