kmail Library API Documentation

kmacctcachedimap.cpp

00001 
00032 #ifdef HAVE_CONFIG_H
00033 #include <config.h>
00034 #endif
00035 
00036 #include "kmacctcachedimap.h"
00037 using KMail::SieveConfig;
00038 
00039 #include "kmfoldertree.h"
00040 #include "kmfoldermgr.h"
00041 #include "kmfiltermgr.h"
00042 #include "kmfoldercachedimap.h"
00043 #include "kmmainwin.h"
00044 #include "kmmainwidget.h"
00045 #include "kmkernel.h"
00046 #include "kmacctmgr.h"
00047 #include "progressmanager.h"
00048 
00049 #include <kio/passdlg.h>
00050 #include <kio/scheduler.h>
00051 #include <kio/slave.h>
00052 #include <kmessagebox.h>
00053 #include <kdebug.h>
00054 #include <kstandarddirs.h>
00055 #include <kapplication.h>
00056 #include <kconfig.h>
00057 
00058 
00059 KMAcctCachedImap::KMAcctCachedImap( KMAcctMgr* aOwner,
00060                     const QString& aAccountName, uint id )
00061   : KMail::ImapAccountBase( aOwner, aAccountName, id ), mFolder( 0 ),
00062     mProgressDialogEnabled( true )
00063 {
00064   // Never EVER set this for the cached IMAP account
00065   mAutoExpunge = false;
00066 }
00067 
00068 
00069 //-----------------------------------------------------------------------------
00070 KMAcctCachedImap::~KMAcctCachedImap()
00071 {
00072   killAllJobsInternal( true );
00073 }
00074 
00075 
00076 //-----------------------------------------------------------------------------
00077 QString KMAcctCachedImap::type() const
00078 {
00079   return "cachedimap";
00080 }
00081 
00082 void KMAcctCachedImap::init() {
00083   ImapAccountBase::init();
00084 
00085   setProgressDialogEnabled( true );
00086 }
00087 
00088 //-----------------------------------------------------------------------------
00089 void KMAcctCachedImap::pseudoAssign( const KMAccount * a ) {
00090   killAllJobs( true );
00091   if (mFolder)
00092   {
00093     mFolder->setContentState(KMFolderCachedImap::imapNoInformation);
00094     mFolder->setSubfolderState(KMFolderCachedImap::imapNoInformation);
00095   }
00096 
00097   setProgressDialogEnabled(static_cast<const KMAcctCachedImap*>(a)->isProgressDialogEnabled());
00098 
00099   ImapAccountBase::pseudoAssign( a );
00100 }
00101 
00102 void KMAcctCachedImap::setPrefixHook() {
00103   if ( mFolder ) mFolder->setImapPath( prefix() );
00104 }
00105 
00106 //-----------------------------------------------------------------------------
00107 void KMAcctCachedImap::setImapFolder(KMFolderCachedImap *aFolder)
00108 {
00109   mFolder = aFolder;
00110   mFolder->setImapPath(mPrefix);
00111   mFolder->setAccount( this );
00112 }
00113 
00114 
00115 //-----------------------------------------------------------------------------
00116 void KMAcctCachedImap::setAutoExpunge( bool /*aAutoExpunge*/ )
00117 {
00118   // Never EVER set this for the cached IMAP account
00119   mAutoExpunge = false;
00120 }
00121 
00122 //-----------------------------------------------------------------------------
00123 void KMAcctCachedImap::killAllJobs( bool disconnectSlave )
00124 {
00125   //kdDebug(5006) << "killAllJobs: disconnectSlave=" << disconnectSlave << "  " << mapJobData.count() << " jobs in map." << endl;
00126   QValueList<KMFolderCachedImap*> folderList = killAllJobsInternal( disconnectSlave );
00127   for( QValueList<KMFolderCachedImap*>::Iterator it = folderList.begin(); it != folderList.end(); ++it ) {
00128     KMFolderCachedImap *fld = *it;
00129     fld->resetSyncState();
00130     fld->setContentState(KMFolderCachedImap::imapNoInformation);
00131     fld->setSubfolderState(KMFolderCachedImap::imapNoInformation);
00132     fld->sendFolderComplete(FALSE);
00133   }
00134 }
00135 
00136 //-----------------------------------------------------------------------------
00137 // Common between killAllJobs and the destructor - which shouldn't call sendFolderComplete
00138 QValueList<KMFolderCachedImap*> KMAcctCachedImap::killAllJobsInternal( bool disconnectSlave )
00139 {
00140   // Make list of folders to reset. This must be done last, since folderComplete
00141   // can trigger the next queued mail check already.
00142   QValueList<KMFolderCachedImap*> folderList;
00143   QMap<KIO::Job*, jobData>::Iterator it = mapJobData.begin();
00144   for (; it != mapJobData.end(); ++it) {
00145     if ((*it).parent)
00146       folderList << static_cast<KMFolderCachedImap*>((*it).parent->storage());
00147     // Kill the job - except if it's the one that already died and is calling us
00148     if ( !it.key()->error() && mSlave ) {
00149       it.key()->kill();
00150       mSlave = 0; // killing a job, kills the slave
00151     }
00152   }
00153   mapJobData.clear();
00154 
00155   // Clear the joblist. Make SURE to stop the job emitting "finished"
00156   for( QPtrListIterator<CachedImapJob> it( mJobList ); it.current(); ++it )
00157     it.current()->setPassiveDestructor( true );
00158   KMAccount::deleteFolderJobs();
00159 
00160   if ( disconnectSlave && mSlave ) {
00161     KIO::Scheduler::disconnectSlave( mSlave );
00162     mSlave = 0;
00163   }
00164   return folderList;
00165 }
00166 
00167 //-----------------------------------------------------------------------------
00168 void KMAcctCachedImap::cancelMailCheck()
00169 {
00170   // Make list of folders to reset, like in killAllJobs
00171   QValueList<KMFolderCachedImap*> folderList;
00172   QMap<KIO::Job*, jobData>::Iterator it = mapJobData.begin();
00173   for (; it != mapJobData.end(); ++it) {
00174     if ( (*it).cancellable && (*it).parent )
00175       folderList << static_cast<KMFolderCachedImap*>((*it).parent->storage());
00176   }
00177   // Kill jobs
00178   ImapAccountBase::cancelMailCheck();
00179   // Reset sync states and emit folderComplete, this is important for
00180   // KMAccount::checkingMail() to be reset, in case we restart checking mail later.
00181   for( QValueList<KMFolderCachedImap*>::Iterator it = folderList.begin(); it != folderList.end(); ++it ) {
00182     KMFolderCachedImap *fld = *it;
00183     fld->resetSyncState();
00184     fld->setContentState(KMFolderCachedImap::imapNoInformation);
00185     fld->setSubfolderState(KMFolderCachedImap::imapNoInformation);
00186     fld->sendFolderComplete(FALSE);
00187   }
00188 }
00189 
00190 //-----------------------------------------------------------------------------
00191 void KMAcctCachedImap::killJobsForItem(KMFolderTreeItem * fti)
00192 {
00193   QMap<KIO::Job *, jobData>::Iterator it = mapJobData.begin();
00194   while (it != mapJobData.end())
00195   {
00196     if (it.data().parent == fti->folder())
00197     {
00198       killAllJobs();
00199       break;
00200     }
00201     else ++it;
00202   }
00203 }
00204 
00205 // Reimplemented from ImapAccountBase because we only check one folder at a time
00206 void KMAcctCachedImap::slotCheckQueuedFolders()
00207 {
00208     mMailCheckFolders.clear();
00209     mMailCheckFolders.append( mFoldersQueuedForChecking.front() );
00210     mFoldersQueuedForChecking.pop_front();
00211     if ( mFoldersQueuedForChecking.isEmpty() )
00212       disconnect( this, SIGNAL( finishedCheck( bool, CheckStatus ) ),
00213                   this, SLOT( slotCheckQueuedFolders() ) );
00214 
00215     kmkernel->acctMgr()->singleCheckMail(this, true);
00216     mMailCheckFolders.clear();
00217 }
00218 
00219 void KMAcctCachedImap::processNewMail( bool interactive )
00220 {
00221   if ( !mFolder ) { // happens if this is a pseudo-account (from configuredialog)
00222     checkDone( false, CheckIgnored );
00223     return;
00224   }
00225   if ( mMailCheckFolders.isEmpty() )
00226    processNewMail( mFolder, interactive, true );
00227   else {
00228     KMFolder* f = mMailCheckFolders.front();
00229     mMailCheckFolders.pop_front();
00230     processNewMail( static_cast<KMFolderCachedImap *>( f->storage() ), interactive, false );
00231   }
00232 }
00233 
00234 void KMAcctCachedImap::processNewMail( KMFolderCachedImap* folder,
00235                        bool interactive,
00236                                        bool recurse )
00237 {
00238   // This should never be set for a cached IMAP account
00239   mAutoExpunge = false;
00240   mCountLastUnread = 0;
00241   mUnreadBeforeCheck.clear();
00242   // stop sending noops during sync, that will keep the connection open
00243   mNoopTimer.stop();
00244 
00245   if( interactive && isProgressDialogEnabled() ) {
00246     // Show progress dialog in all listeners.
00247     KPIM::ProgressManager::emitShowProgressDialog();
00248   }
00249 
00250   Q_ASSERT( !mMailCheckProgressItem );
00251   mMailCheckProgressItem = KPIM::ProgressManager::createProgressItem(
00252     "MailCheck" + QString::number( id() ),
00253     folder->label(), // will be changed immediately in serverSync anyway
00254     QString::null,
00255     true, // can be cancelled
00256     useSSL() || useTLS() );
00257   connect( mMailCheckProgressItem, SIGNAL( progressItemCanceled( ProgressItem* ) ),
00258            this, SLOT( slotProgressItemCanceled( ProgressItem* ) ) );
00259 
00260   folder->setAccount(this);
00261   connect(folder, SIGNAL(folderComplete(KMFolderCachedImap*, bool)),
00262       this, SLOT(postProcessNewMail(KMFolderCachedImap*, bool)));
00263   folder->serverSync( recurse );
00264 }
00265 
00266 void KMAcctCachedImap::postProcessNewMail( KMFolderCachedImap* folder, bool )
00267 {
00268   mNoopTimer.start( 60000 ); // send a noop every minute to avoid "connection broken" errors
00269   disconnect(folder, SIGNAL(folderComplete(KMFolderCachedImap*, bool)),
00270              this, SLOT(postProcessNewMail(KMFolderCachedImap*, bool)));
00271   mMailCheckProgressItem->setComplete();
00272   mMailCheckProgressItem = 0;
00273 
00274   if ( folder == mFolder ) {
00275     // We remove everything from the deleted folders list after a full sync.
00276     // Even if it fails (no permission), because on the next sync we want the folder to reappear,
00277     //  instead of the user being stuck with "can't delete" every time.
00278     // And we do it for _all_ deleted folders, even those that were deleted on the server in the first place (slotListResult).
00279     //  Otherwise this might have side effects much later (e.g. when regaining permissions to a folder we could see before)
00280 
00281 #if 0 // this opens a race: delete a folder during a sync (after the sync checked that folder), and it'll be forgotten...
00282     mDeletedFolders.clear();
00283 #endif
00284     mPreviouslyDeletedFolders.clear();
00285   }
00286 
00287   KMail::ImapAccountBase::postProcessNewMail();
00288 }
00289 
00290 void KMAcctCachedImap::addUnreadMsgCount( const KMFolderCachedImap *folder,
00291                                           int countUnread )
00292 {
00293   if ( folder->imapPath() != "/INBOX/" ) {
00294     // new mail in INBOX is processed with KMAccount::processNewMsg() and
00295     // therefore doesn't need to be counted here
00296     const QString folderId = folder->folder()->idString();
00297     int newInFolder = countUnread;
00298     if ( mUnreadBeforeCheck.find( folderId ) != mUnreadBeforeCheck.end() )
00299       newInFolder -= mUnreadBeforeCheck[folderId];
00300     if ( newInFolder > 0 )
00301       addToNewInFolder( folderId, newInFolder );
00302   }
00303   mCountUnread += countUnread;
00304 }
00305 
00306 void KMAcctCachedImap::addLastUnreadMsgCount( const KMFolderCachedImap *folder,
00307                                               int countLastUnread )
00308 {
00309   mUnreadBeforeCheck[folder->folder()->idString()] = countLastUnread;
00310   mCountLastUnread += countLastUnread;
00311 }
00312 
00313 //
00314 //
00315 // read/write config
00316 //
00317 //
00318 
00319 void KMAcctCachedImap::readConfig( /*const*/ KConfig/*Base*/ & config ) {
00320   ImapAccountBase::readConfig( config );
00321   setProgressDialogEnabled( config.readBoolEntry( "progressdialog", true ) );
00322   // Apparently this method is only ever called once (from KMKernel::init) so this is ok
00323   mPreviouslyDeletedFolders = config.readListEntry( "deleted-folders" );
00324   mDeletedFolders.clear(); // but just in case...
00325   const QStringList oldPaths = config.readListEntry( "renamed-folders-paths" );
00326   const QStringList newNames = config.readListEntry( "renamed-folders-names" );
00327   QStringList::const_iterator it = oldPaths.begin();
00328   QStringList::const_iterator nameit = newNames.begin();
00329   for( ; it != oldPaths.end() && nameit != newNames.end(); ++it, ++nameit ) {
00330     addRenamedFolder( *it, QString::null, *nameit );
00331   }
00332 }
00333 
00334 void KMAcctCachedImap::writeConfig( KConfig/*Base*/ & config ) /*const*/ {
00335   ImapAccountBase::writeConfig( config );
00336   config.writeEntry( "progressdialog", isProgressDialogEnabled() );
00337   config.writeEntry( "deleted-folders", mDeletedFolders + mPreviouslyDeletedFolders );
00338   config.writeEntry( "renamed-folders-paths", mRenamedFolders.keys() );
00339   const QValueList<RenamedFolder> values = mRenamedFolders.values();
00340   QStringList lstNames;
00341   QValueList<RenamedFolder>::const_iterator it = values.begin();
00342   for ( ; it != values.end() ; ++it )
00343     lstNames.append( (*it).mNewName );
00344   config.writeEntry( "renamed-folders-names", lstNames );
00345 }
00346 
00347 void KMAcctCachedImap::invalidateIMAPFolders()
00348 {
00349   invalidateIMAPFolders( mFolder );
00350 }
00351 
00352 void KMAcctCachedImap::invalidateIMAPFolders( KMFolderCachedImap* folder )
00353 {
00354   if( !folder || !folder->folder() )
00355     return;
00356 
00357   folder->setAccount(this);
00358 
00359   QStringList strList;
00360   QValueList<QGuardedPtr<KMFolder> > folderList;
00361   kmkernel->dimapFolderMgr()->createFolderList( &strList, &folderList,
00362                         folder->folder()->child(), QString::null,
00363                         false );
00364   QValueList<QGuardedPtr<KMFolder> >::Iterator it;
00365   mCountLastUnread = 0;
00366   mUnreadBeforeCheck.clear();
00367 
00368   for( it = folderList.begin(); it != folderList.end(); ++it ) {
00369     KMFolder *f = *it;
00370     if( f && f->folderType() == KMFolderTypeCachedImap ) {
00371       KMFolderCachedImap *cfolder = static_cast<KMFolderCachedImap*>(f->storage());
00372       // This invalidates the folder completely
00373       cfolder->setUidValidity("INVALID");
00374       cfolder->writeUidCache();
00375       processNewMailSingleFolder( f );
00376     }
00377   }
00378   folder->setUidValidity("INVALID");
00379   folder->writeUidCache();
00380 
00381   processNewMailSingleFolder( folder->folder() );
00382 }
00383 
00384 //-----------------------------------------------------------------------------
00385 void KMAcctCachedImap::addDeletedFolder( KMFolder* folder )
00386 {
00387   if ( folder->folderType() != KMFolderTypeCachedImap )
00388     return;
00389   KMFolderCachedImap* storage = static_cast<KMFolderCachedImap*>(folder->storage());
00390   addDeletedFolder( storage->imapPath() );
00391   kdDebug(5006) << k_funcinfo << storage->imapPath() << endl;
00392 
00393   // Add all child folders too
00394   if( folder && folder->child() ) {
00395     KMFolderNode *node = folder->child()->first();
00396     while( node ) {
00397       if( !node->isDir() ) {
00398         addDeletedFolder( static_cast<KMFolder*>( node ) ); // recurse
00399       }
00400       node = folder->child()->next();
00401     }
00402   }
00403 }
00404 
00405 void KMAcctCachedImap::addDeletedFolder( const QString& imapPath )
00406 {
00407   mDeletedFolders << imapPath;
00408 }
00409 
00410 QStringList KMAcctCachedImap::deletedFolderPaths( const QString& subFolderPath ) const
00411 {
00412   QStringList lst;
00413   for ( QStringList::const_iterator it = mDeletedFolders.begin(); it != mDeletedFolders.end(); ++it ) {
00414     if ( (*it).startsWith( subFolderPath ) )
00415       // We must reverse the order, so that sub sub sub folders are deleted first
00416       lst.prepend( *it );
00417   }
00418   for ( QStringList::const_iterator it = mPreviouslyDeletedFolders.begin(); it != mPreviouslyDeletedFolders.end(); ++it ) {
00419     if ( (*it).startsWith( subFolderPath ) )
00420       lst.prepend( *it );
00421   }
00422   kdDebug(5006) << "KMAcctCachedImap::deletedFolderPaths for " << subFolderPath << " returning: " << lst << endl;
00423   Q_ASSERT( !lst.isEmpty() );
00424   return lst;
00425 }
00426 
00427 bool KMAcctCachedImap::isDeletedFolder( const QString& subFolderPath ) const
00428 {
00429   return mDeletedFolders.find( subFolderPath ) != mDeletedFolders.end();
00430 }
00431 
00432 bool KMAcctCachedImap::isPreviouslyDeletedFolder( const QString& subFolderPath ) const
00433 {
00434   return mPreviouslyDeletedFolders.find( subFolderPath ) != mPreviouslyDeletedFolders.end();
00435 }
00436 
00437 void KMAcctCachedImap::removeDeletedFolder( const QString& subFolderPath )
00438 {
00439   mDeletedFolders.remove( subFolderPath );
00440   mPreviouslyDeletedFolders.remove( subFolderPath );
00441 }
00442 
00443 void KMAcctCachedImap::addRenamedFolder( const QString& subFolderPath, const QString& oldLabel, const QString& newName )
00444 {
00445   mRenamedFolders.insert( subFolderPath, RenamedFolder( oldLabel, newName ) );
00446 }
00447 
00448 void KMAcctCachedImap::removeRenamedFolder( const QString& subFolderPath )
00449 {
00450   mRenamedFolders.remove( subFolderPath );
00451 }
00452 
00453 void KMAcctCachedImap::slotProgressItemCanceled( ProgressItem* )
00454 {
00455   bool abortConnection = !mSlaveConnected;
00456   killAllJobs( abortConnection );
00457   if ( abortConnection ) {
00458     // If we were trying to connect, tell kmfoldercachedimap so that it moves on
00459     emit connectionResult( KIO::ERR_USER_CANCELED, QString::null );
00460   }
00461 }
00462 
00463 FolderStorage* const KMAcctCachedImap::rootFolder() const
00464 {
00465   return mFolder;
00466 }
00467 
00468 
00469 QString KMAcctCachedImap::renamedFolder( const QString& imapPath ) const
00470 {
00471   QMap<QString, RenamedFolder>::ConstIterator renit = mRenamedFolders.find( imapPath );
00472   if ( renit != mRenamedFolders.end() )
00473     return (*renit).mNewName;
00474   return QString::null;
00475 }
00476 
00477 #include "kmacctcachedimap.moc"
KDE Logo
This file is part of the documentation for kmail Library Version 3.3.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Jul 25 11:19:58 2007 by doxygen 1.4.2 written by Dimitri van Heesch, © 1997-2003