00001
00022 #ifdef HAVE_CONFIG_H
00023 #include <config.h>
00024 #endif
00025
00026 #include "kmacctimap.h"
00027 using KMail::SieveConfig;
00028
00029 #include "kmmessage.h"
00030 #include "broadcaststatus.h"
00031 using KPIM::BroadcastStatus;
00032 #include "kmfoldertree.h"
00033 #include "kmfoldermgr.h"
00034 #include "kmfolderimap.h"
00035 #include "kmmainwin.h"
00036 #include "kmmsgdict.h"
00037 #include "kmfilter.h"
00038 #include "kmfiltermgr.h"
00039 #include "folderstorage.h"
00040 #include "imapjob.h"
00041 #include "actionscheduler.h"
00042 using KMail::ActionScheduler;
00043 using KMail::ImapJob;
00044 using KMail::ImapAccountBase;
00045 #include "progressmanager.h"
00046 using KPIM::ProgressItem;
00047 using KPIM::ProgressManager;
00048 #include <kio/scheduler.h>
00049 #include <kio/slave.h>
00050 #include <kmessagebox.h>
00051 #include <kdebug.h>
00052
00053 #include <qstylesheet.h>
00054
00055 #include <errno.h>
00056
00057
00058 KMAcctImap::KMAcctImap(AccountManager* aOwner, const QString& aAccountName, uint id):
00059 KMail::ImapAccountBase(aOwner, aAccountName, id),
00060 mCountRemainChecks( 0 ),
00061 mErrorTimer( 0, "mErrorTimer" )
00062 {
00063 mFolder = 0;
00064 mScheduler = 0;
00065 mNoopTimer.start( 60000 );
00066 mOpenFolders.setAutoDelete(true);
00067 connect(kmkernel->imapFolderMgr(), SIGNAL(changed()),
00068 this, SLOT(slotUpdateFolderList()));
00069 connect(&mErrorTimer, SIGNAL(timeout()), SLOT(slotResetConnectionError()));
00070
00071 QString serNumUri = locateLocal( "data", "kmail/unfiltered." +
00072 QString("%1").arg(KAccount::id()) );
00073 KConfig config( serNumUri );
00074 QStringList serNums = config.readListEntry( "unfiltered" );
00075 mFilterSerNumsToSave.setAutoDelete( false );
00076
00077 for ( QStringList::ConstIterator it = serNums.begin();
00078 it != serNums.end(); ++it ) {
00079 mFilterSerNums.append( (*it).toUInt() );
00080 mFilterSerNumsToSave.insert( *it, (const int *)1 );
00081 }
00082 }
00083
00084
00085
00086 KMAcctImap::~KMAcctImap()
00087 {
00088 killAllJobs( true );
00089
00090 QString serNumUri = locateLocal( "data", "kmail/unfiltered." +
00091 QString("%1").arg(KAccount::id()) );
00092 KConfig config( serNumUri );
00093 QStringList serNums;
00094 QDictIterator<int> it( mFilterSerNumsToSave );
00095 for( ; it.current(); ++it )
00096 serNums.append( it.currentKey() );
00097 config.writeEntry( "unfiltered", serNums );
00098 }
00099
00100
00101
00102 QString KMAcctImap::type() const
00103 {
00104 return "imap";
00105 }
00106
00107
00108 void KMAcctImap::pseudoAssign( const KMAccount * a ) {
00109 killAllJobs( true );
00110 if (mFolder)
00111 {
00112 mFolder->setContentState(KMFolderImap::imapNoInformation);
00113 mFolder->setSubfolderState(KMFolderImap::imapNoInformation);
00114 }
00115 ImapAccountBase::pseudoAssign( a );
00116 }
00117
00118
00119 void KMAcctImap::setImapFolder(KMFolderImap *aFolder)
00120 {
00121 mFolder = aFolder;
00122 mFolder->setImapPath( "/" );
00123 }
00124
00125
00126
00127
00128 bool KMAcctImap::handleError( int errorCode, const QString &errorMsg, KIO::Job* job, const QString& context, bool abortSync )
00129 {
00130
00131 if ( errorCode == KIO::ERR_DOES_NOT_EXIST ) {
00132
00133 if ( mFolder )
00134 mFolder->listDirectory();
00135 return true;
00136 }
00137 return ImapAccountBase::handleError( errorCode, errorMsg, job, context, abortSync );
00138 }
00139
00140
00141
00142 void KMAcctImap::killAllJobs( bool disconnectSlave )
00143 {
00144 QMap<KIO::Job*, jobData>::Iterator it = mapJobData.begin();
00145 for ( ; it != mapJobData.end(); ++it)
00146 {
00147 QPtrList<KMMessage> msgList = (*it).msgList;
00148 QPtrList<KMMessage>::Iterator it2 = msgList.begin();
00149 for ( ; it2 != msgList.end(); ++it2 ) {
00150 KMMessage *msg = *it2;
00151 if ( msg->transferInProgress() ) {
00152 kdDebug(5006) << "KMAcctImap::killAllJobs - resetting mail" << endl;
00153 msg->setTransferInProgress( false );
00154 }
00155 }
00156 if ((*it).parent)
00157 {
00158
00159 KMFolderImap *fld = static_cast<KMFolderImap*>((*it).parent->storage());
00160 fld->setCheckingValidity(false);
00161 fld->quiet(false);
00162 fld->setContentState(KMFolderImap::imapNoInformation);
00163 fld->setSubfolderState(KMFolderImap::imapNoInformation);
00164 fld->sendFolderComplete(FALSE);
00165 fld->removeJobs();
00166 }
00167 if ( (*it).progressItem )
00168 {
00169 (*it).progressItem->setComplete();
00170 }
00171 }
00172 if (mSlave && mapJobData.begin() != mapJobData.end())
00173 {
00174 mSlave->kill();
00175 mSlave = 0;
00176 }
00177
00178 mapJobData.clear();
00179
00180
00181 KMAccount::deleteFolderJobs();
00182 QPtrListIterator<ImapJob> it2( mJobList );
00183 while ( it2.current() ) {
00184 ImapJob *job = it2.current();
00185 ++it2;
00186 job->kill();
00187 }
00188 mJobList.clear();
00189
00190 if (mCountRemainChecks > 0)
00191 {
00192 checkDone( false, CheckOK );
00193 mCountRemainChecks = 0;
00194 }
00195 if ( disconnectSlave && slave() ) {
00196 KIO::Scheduler::disconnectSlave( slave() );
00197 mSlave = 0;
00198 }
00199 }
00200
00201
00202 void KMAcctImap::ignoreJobsForMessage( KMMessage* msg )
00203 {
00204 if (!msg) return;
00205 QPtrListIterator<ImapJob> it( mJobList );
00206 while ( it.current() )
00207 {
00208 ImapJob *job = it.current();
00209 ++it;
00210 if ( job->msgList().first() == msg )
00211 {
00212 job->kill();
00213 }
00214 }
00215 }
00216
00217
00218 void KMAcctImap::ignoreJobsForFolder( KMFolder* folder )
00219 {
00220 QPtrListIterator<ImapJob> it( mJobList );
00221 while ( it.current() )
00222 {
00223 ImapJob *job = it.current();
00224 ++it;
00225 if ( !job->msgList().isEmpty() && job->msgList().first()->parent() == folder )
00226 {
00227 job->kill();
00228 }
00229 }
00230 }
00231
00232
00233 void KMAcctImap::removeSlaveJobsForFolder( KMFolder* folder )
00234 {
00235
00236 QMap<KIO::Job*, jobData>::Iterator it = mapJobData.begin();
00237 while ( it != mapJobData.end() ) {
00238 QMap<KIO::Job*, jobData>::Iterator i = it;
00239 it++;
00240 if ( (*i).parent ) {
00241 if ( (*i).parent == folder ) {
00242 mapJobData.remove(i);
00243 }
00244 }
00245 }
00246 }
00247
00248
00249 void KMAcctImap::cancelMailCheck()
00250 {
00251
00252 QValueList<KMFolderImap*> folderList;
00253 QMap<KIO::Job*, jobData>::Iterator it = mapJobData.begin();
00254 for (; it != mapJobData.end(); ++it) {
00255 if ( (*it).cancellable && (*it).parent ) {
00256 folderList << static_cast<KMFolderImap*>((*it).parent->storage());
00257 }
00258 }
00259
00260
00261
00262 killAllJobs( true );
00263
00264
00265 for( QValueList<KMFolderImap*>::Iterator it = folderList.begin(); it != folderList.end(); ++it ) {
00266 KMFolderImap *fld = *it;
00267 fld->sendFolderComplete(FALSE);
00268 }
00269 }
00270
00271
00272 void KMAcctImap::processNewMail(bool interactive)
00273 {
00274 kdDebug() << "processNewMail " << mCheckingSingleFolder << ",status="<<makeConnection()<<endl;
00275 if (!mFolder || !mFolder->folder() || !mFolder->folder()->child() ||
00276 makeConnection() == ImapAccountBase::Error)
00277 {
00278
00279 checkDone( false, CheckError );
00280 mCountRemainChecks = 0;
00281 mCheckingSingleFolder = false;
00282 return;
00283 }
00284
00285 if( mMailCheckFolders.isEmpty() )
00286 {
00287 slotUpdateFolderList();
00288
00289 if( mMailCheckFolders.isEmpty() )
00290 {
00291 checkDone( false, CheckOK );
00292 mCheckingSingleFolder = false;
00293 return;
00294 }
00295 }
00296
00297 Q_ASSERT( !mMailCheckProgressItem );
00298 mMailCheckProgressItem =
00299 ProgressManager::createProgressItem(
00300 "MailCheckAccount" + name(),
00301 i18n("Checking account: %1" ).arg( QStyleSheet::escape( name() ) ),
00302 QString::null,
00303 true,
00304 useSSL() || useTLS() );
00305
00306 mMailCheckProgressItem->setTotalItems( mMailCheckFolders.count() );
00307 connect ( mMailCheckProgressItem,
00308 SIGNAL( progressItemCanceled( KPIM::ProgressItem*) ),
00309 this,
00310 SLOT( slotMailCheckCanceled() ) );
00311
00312 QValueList<QGuardedPtr<KMFolder> >::Iterator it;
00313
00314 mCountRemainChecks = 0;
00315 mCountUnread = 0;
00316 mUnreadBeforeCheck.clear();
00317 for (it = mMailCheckFolders.begin(); it != mMailCheckFolders.end(); ++it)
00318 {
00319 KMFolder *folder = *it;
00320 if (folder && !folder->noContent())
00321 {
00322 mUnreadBeforeCheck[folder->idString()] = folder->countUnread();
00323 }
00324 }
00325 bool gotError = false;
00326
00327 for (it = mMailCheckFolders.begin(); it != mMailCheckFolders.end(); ++it)
00328 {
00329 KMFolder *folder = *it;
00330 if (folder && !folder->noContent())
00331 {
00332 KMFolderImap *imapFolder = static_cast<KMFolderImap*>(folder->storage());
00333 if ( imapFolder->getContentState() != KMFolderImap::imapListingInProgress
00334 && imapFolder->getContentState() != KMFolderImap::imapDownloadInProgress )
00335 {
00336
00337 mCountRemainChecks++;
00338
00339 if (imapFolder->isSelected()) {
00340 connect(imapFolder, SIGNAL(folderComplete(KMFolderImap*, bool)),
00341 this, SLOT(postProcessNewMail(KMFolderImap*, bool)));
00342 imapFolder->getFolder();
00343 } else if ( kmkernel->filterMgr()->atLeastOneIncomingFilterAppliesTo( id() ) &&
00344 imapFolder->folder()->isSystemFolder() &&
00345 imapFolder->imapPath() == "/INBOX/" ) {
00346 imapFolder->open("acctimap");
00347
00348 imapFolder->setSelected( true );
00349 connect( imapFolder, SIGNAL( folderComplete( KMFolderImap*, bool ) ),
00350 this, SLOT( slotFolderSelected( KMFolderImap*, bool) ) );
00351 imapFolder->getFolder();
00352 }
00353 else {
00354 connect(imapFolder, SIGNAL(numUnreadMsgsChanged(KMFolder*)),
00355 this, SLOT(postProcessNewMail(KMFolder*)));
00356 bool ok = imapFolder->processNewMail(interactive);
00357 if (!ok)
00358 {
00359
00360 mCountRemainChecks--;
00361 gotError = true;
00362 if ( mMailCheckProgressItem ) {
00363 mMailCheckProgressItem->incCompletedItems();
00364 mMailCheckProgressItem->updateProgress();
00365 }
00366
00367 break;
00368 }
00369 }
00370 }
00371 }
00372 }
00373 if ( gotError )
00374 slotUpdateFolderList();
00375
00376 if ( mCountRemainChecks == 0 )
00377 {
00378 mCountLastUnread = 0;
00379 ImapAccountBase::postProcessNewMail();
00380 mUnreadBeforeCheck.clear();
00381 mCheckingSingleFolder = false;
00382 }
00383 }
00384
00385
00386 void KMAcctImap::postProcessNewMail(KMFolderImap* folder, bool)
00387 {
00388 disconnect(folder, SIGNAL(folderComplete(KMFolderImap*, bool)),
00389 this, SLOT(postProcessNewMail(KMFolderImap*, bool)));
00390 postProcessNewMail(static_cast<KMFolder*>(folder->folder()));
00391 }
00392
00393 void KMAcctImap::postProcessNewMail( KMFolder * folder )
00394 {
00395 disconnect( folder->storage(), SIGNAL(numUnreadMsgsChanged(KMFolder*)),
00396 this, SLOT(postProcessNewMail(KMFolder*)) );
00397
00398 if ( mMailCheckProgressItem ) {
00399 mMailCheckProgressItem->incCompletedItems();
00400 mMailCheckProgressItem->updateProgress();
00401 mMailCheckProgressItem->setStatus( folder->prettyURL() + i18n(" completed") );
00402 }
00403 mCountRemainChecks--;
00404
00405
00406 const QString folderId = folder->idString();
00407 int newInFolder = folder->countUnread();
00408 if ( mUnreadBeforeCheck.find( folderId ) != mUnreadBeforeCheck.end() )
00409 newInFolder -= mUnreadBeforeCheck[folderId];
00410 if ( newInFolder > 0 ) {
00411 addToNewInFolder( folderId, newInFolder );
00412 mCountUnread += newInFolder;
00413 }
00414
00415
00416 QValueListIterator<Q_UINT32> filterIt = mFilterSerNums.begin();
00417 QValueList<Q_UINT32> inTransit;
00418
00419 if (ActionScheduler::isEnabled() ||
00420 kmkernel->filterMgr()->atLeastOneOnlineImapFolderTarget()) {
00421 KMFilterMgr::FilterSet set = KMFilterMgr::Inbound;
00422 QValueList<KMFilter*> filters = kmkernel->filterMgr()->filters();
00423 if (!mScheduler) {
00424 mScheduler = new KMail::ActionScheduler( set, filters );
00425 mScheduler->setAccountId( id() );
00426 connect( mScheduler, SIGNAL(filtered(Q_UINT32)), this, SLOT(slotFiltered(Q_UINT32)) );
00427 } else {
00428 mScheduler->setFilterList( filters );
00429 }
00430 }
00431
00432 while (filterIt != mFilterSerNums.end()) {
00433 int idx = -1;
00434 KMFolder *folder = 0;
00435 KMMessage *msg = 0;
00436 KMMsgDict::instance()->getLocation( *filterIt, &folder, &idx );
00437
00438
00439 if ( !folder ) {
00440 mFilterSerNumsToSave.remove( QString( "%1" ).arg( *filterIt ) );
00441 ++filterIt;
00442 continue;
00443 }
00444
00445 KMFolderImap *imapFolder = dynamic_cast<KMFolderImap*>(folder->storage());
00446 if (!imapFolder ||
00447 !imapFolder->folder()->isSystemFolder() ||
00448 !(imapFolder->imapPath() == "/INBOX/") ) {
00449 mFilterSerNumsToSave.remove( QString( "%1" ).arg( *filterIt ) );
00450 ++filterIt;
00451 continue;
00452 }
00453
00454 if (idx != -1) {
00455
00456 msg = folder->getMsg( idx );
00457 if (!msg) {
00458 mFilterSerNumsToSave.remove( QString( "%1" ).arg( *filterIt ) );
00459 ++filterIt;
00460 continue;
00461 }
00462
00463 if (ActionScheduler::isEnabled() ||
00464 kmkernel->filterMgr()->atLeastOneOnlineImapFolderTarget()) {
00465 mScheduler->execFilters( msg );
00466 } else {
00467 if (msg->transferInProgress()) {
00468 inTransit.append( *filterIt );
00469 ++filterIt;
00470 continue;
00471 }
00472 msg->setTransferInProgress(true);
00473 if ( !msg->isComplete() ) {
00474 FolderJob *job = folder->createJob(msg);
00475 connect(job, SIGNAL(messageRetrieved(KMMessage*)),
00476 SLOT(slotFilterMsg(KMMessage*)));
00477 job->start();
00478 } else {
00479 mFilterSerNumsToSave.remove( QString( "%1" ).arg( *filterIt ) );
00480 if (slotFilterMsg(msg) == 2) break;
00481 }
00482 }
00483 }
00484 ++filterIt;
00485 }
00486 mFilterSerNums = inTransit;
00487
00488 if (mCountRemainChecks == 0)
00489 {
00490
00491 mCountLastUnread = 0;
00492
00493
00494 bool showStatus = ( mCheckingSingleFolder && mCountUnread > 0 ) ? false : true;
00495 ImapAccountBase::postProcessNewMail( showStatus );
00496 mUnreadBeforeCheck.clear();
00497 mCheckingSingleFolder = false;
00498 }
00499 }
00500
00501
00502 void KMAcctImap::slotFiltered(Q_UINT32 serNum)
00503 {
00504 mFilterSerNumsToSave.remove( QString( "%1" ).arg( serNum ) );
00505 }
00506
00507
00508 void KMAcctImap::slotUpdateFolderList()
00509 {
00510 if ( !mFolder || !mFolder->folder() || !mFolder->folder()->child() )
00511 {
00512 kdWarning(5006) << "KMAcctImap::slotUpdateFolderList return" << endl;
00513 return;
00514 }
00515 QStringList strList;
00516 mMailCheckFolders.clear();
00517 kmkernel->imapFolderMgr()->createFolderList(&strList, &mMailCheckFolders,
00518 mFolder->folder()->child(), QString::null, false);
00519
00520 QValueList<QGuardedPtr<KMFolder> > includedFolders;
00521
00522 QValueList<QGuardedPtr<KMFolder> >::Iterator it;
00523 for (it = mMailCheckFolders.begin(); it != mMailCheckFolders.end(); ++it)
00524 {
00525 KMFolderImap* folder = static_cast<KMFolderImap*>(((KMFolder*)(*it))->storage());
00526 if (folder->includeInMailCheck())
00527 includedFolders.append(*it);
00528 }
00529 mMailCheckFolders = includedFolders;
00530 }
00531
00532
00533 void KMAcctImap::listDirectory()
00534 {
00535 mFolder->listDirectory();
00536 }
00537
00538
00539 void KMAcctImap::readConfig(KConfig& config)
00540 {
00541 ImapAccountBase::readConfig( config );
00542 }
00543
00544
00545 void KMAcctImap::slotMailCheckCanceled()
00546 {
00547 if( mMailCheckProgressItem )
00548 mMailCheckProgressItem->setComplete();
00549 cancelMailCheck();
00550 }
00551
00552
00553 FolderStorage* const KMAcctImap::rootFolder() const
00554 {
00555 return mFolder;
00556 }
00557
00558 ImapAccountBase::ConnectionState KMAcctImap::makeConnection()
00559 {
00560 if ( mSlaveConnectionError )
00561 {
00562 mErrorTimer.start(100, true);
00563 return Error;
00564 }
00565 return ImapAccountBase::makeConnection();
00566 }
00567
00568 void KMAcctImap::slotResetConnectionError()
00569 {
00570 mSlaveConnectionError = false;
00571 kdDebug(5006) << k_funcinfo << endl;
00572 }
00573
00574 void KMAcctImap::slotFolderSelected( KMFolderImap* folder, bool )
00575 {
00576 folder->setSelected( false );
00577 disconnect( folder, SIGNAL( folderComplete( KMFolderImap*, bool ) ),
00578 this, SLOT( slotFolderSelected( KMFolderImap*, bool) ) );
00579 postProcessNewMail( static_cast<KMFolder*>(folder->folder()) );
00580 folder->close( "acctimap" );
00581 }
00582
00583 void KMAcctImap::execFilters(Q_UINT32 serNum)
00584 {
00585 if ( !kmkernel->filterMgr()->atLeastOneFilterAppliesTo( id() ) ) return;
00586 QValueListIterator<Q_UINT32> findIt = mFilterSerNums.find( serNum );
00587 if ( findIt != mFilterSerNums.end() )
00588 return;
00589 mFilterSerNums.append( serNum );
00590 mFilterSerNumsToSave.insert( QString( "%1" ).arg( serNum ), (const int *)1 );
00591 }
00592
00593 int KMAcctImap::slotFilterMsg( KMMessage *msg )
00594 {
00595 if ( !msg ) {
00596
00597 return -1;
00598 }
00599 msg->setTransferInProgress(false);
00600 Q_UINT32 serNum = msg->getMsgSerNum();
00601 if ( serNum )
00602 mFilterSerNumsToSave.remove( QString( "%1" ).arg( serNum ) );
00603
00604 int filterResult = kmkernel->filterMgr()->process(msg,
00605 KMFilterMgr::Inbound,
00606 true,
00607 id() );
00608 if (filterResult == 2) {
00609
00610 kmkernel->emergencyExit( i18n("Unable to process messages: " ) + QString::fromLocal8Bit(strerror(errno)));
00611 return 2;
00612 }
00613 if (msg->parent()) {
00614 int idx = -1;
00615 KMFolder * p = 0;
00616 KMMsgDict::instance()->getLocation( msg, &p, &idx );
00617 assert( p == msg->parent() ); assert( idx >= 0 );
00618 p->unGetMsg( idx );
00619 }
00620
00621 return filterResult;
00622 }
00623
00624 #include "kmacctimap.moc"