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