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