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