00001
00032 #include "kmacctcachedimap.h"
00033 using KMail::SieveConfig;
00034
00035 #include "kmfoldertree.h"
00036 #include "kmfoldermgr.h"
00037 #include "kmfiltermgr.h"
00038 #include "kmfoldercachedimap.h"
00039 #include "kmmainwin.h"
00040 #include "accountmanager.h"
00041 using KMail::AccountManager;
00042 #include "progressmanager.h"
00043
00044 #include <kio/passworddialog.h>
00045 #include <kio/scheduler.h>
00046 #include <kio/slave.h>
00047 #include <kdebug.h>
00048 #include <kstandarddirs.h>
00049 #include <kconfiggroup.h>
00050
00051 #include <QList>
00052
00053 KMAcctCachedImap::KMAcctCachedImap( AccountManager* aOwner,
00054 const QString& aAccountName, uint id )
00055 : KMail::ImapAccountBase( aOwner, aAccountName, id ), mFolder( 0 ),
00056 mAnnotationCheckPassed(false),
00057 mGroupwareType( GroupwareKolab ),
00058 mSentCustomLoginCommand(false)
00059 {
00060
00061 mAutoExpunge = false;
00062 }
00063
00064
00065
00066 KMAcctCachedImap::~KMAcctCachedImap()
00067 {
00068 killAllJobsInternal( true );
00069 }
00070
00071
00072
00073 void KMAcctCachedImap::init() {
00074 ImapAccountBase::init();
00075 }
00076
00077
00078 void KMAcctCachedImap::pseudoAssign( const KMAccount * a ) {
00079 killAllJobs( true );
00080 if (mFolder)
00081 {
00082 mFolder->setContentState(KMFolderCachedImap::imapNoInformation);
00083 mFolder->setSubfolderState(KMFolderCachedImap::imapNoInformation);
00084 }
00085 ImapAccountBase::pseudoAssign( a );
00086 }
00087
00088
00089 void KMAcctCachedImap::setImapFolder(KMFolderCachedImap *aFolder)
00090 {
00091 mFolder = aFolder;
00092 mFolder->setImapPath( "/" );
00093 mFolder->setAccount( this );
00094 }
00095
00096
00097
00098 void KMAcctCachedImap::setAutoExpunge( bool )
00099 {
00100
00101 mAutoExpunge = false;
00102 }
00103
00104
00105 void KMAcctCachedImap::killAllJobs( bool disconnectSlave )
00106 {
00107
00108 QList<KMFolderCachedImap*> folderList = killAllJobsInternal( disconnectSlave );
00109 for( QList<KMFolderCachedImap*>::Iterator it = folderList.begin(); it != folderList.end(); ++it ) {
00110 KMFolderCachedImap *fld = *it;
00111 fld->resetSyncState();
00112 fld->setContentState(KMFolderCachedImap::imapNoInformation);
00113 fld->setSubfolderState(KMFolderCachedImap::imapNoInformation);
00114 fld->sendFolderComplete(false);
00115 }
00116 }
00117
00118
00119
00120 QList<KMFolderCachedImap*> KMAcctCachedImap::killAllJobsInternal( bool disconnectSlave )
00121 {
00122
00123
00124 QList<KMFolderCachedImap*> folderList;
00125 QMap<KJob*, jobData>::Iterator it = mapJobData.begin();
00126 for (; it != mapJobData.end(); ++it) {
00127 if ((*it).parent)
00128 folderList << static_cast<KMFolderCachedImap*>((*it).parent->storage());
00129
00130 if ( mSlave && !it.key()->error() ) {
00131 it.key()->kill();
00132 mSlave = 0;
00133 }
00134 }
00135 mapJobData.clear();
00136
00137
00138 QList<CachedImapJob*>::const_iterator jt;
00139 for( jt = mJobList.constBegin(); jt != mJobList.constEnd(); ++jt )
00140 (*jt)->setPassiveDestructor( true );
00141 KMAccount::deleteFolderJobs();
00142
00143 if ( disconnectSlave && mSlave ) {
00144 KIO::Scheduler::disconnectSlave( mSlave );
00145 mSlave = 0;
00146 }
00147 return folderList;
00148 }
00149
00150
00151 void KMAcctCachedImap::cancelMailCheck()
00152 {
00153
00154 QList<KMFolderCachedImap*> folderList;
00155 QMap<KJob*, jobData>::Iterator it = mapJobData.begin();
00156 for (; it != mapJobData.end(); ++it) {
00157 if ( (*it).cancellable && (*it).parent )
00158 folderList << static_cast<KMFolderCachedImap*>((*it).parent->storage());
00159 }
00160
00161 ImapAccountBase::cancelMailCheck();
00162
00163
00164 for( QList<KMFolderCachedImap*>::Iterator it = folderList.begin(); it != folderList.end(); ++it ) {
00165 KMFolderCachedImap *fld = *it;
00166 fld->resetSyncState();
00167 fld->setContentState(KMFolderCachedImap::imapNoInformation);
00168 fld->setSubfolderState(KMFolderCachedImap::imapNoInformation);
00169 fld->sendFolderComplete(false);
00170 }
00171 }
00172
00173
00174 void KMAcctCachedImap::killJobsForItem(KMFolderTreeItem * fti)
00175 {
00176 QMap<KJob *, jobData>::Iterator it = mapJobData.begin();
00177 while (it != mapJobData.end())
00178 {
00179 if (it.value().parent == fti->folder())
00180 {
00181 killAllJobs();
00182 break;
00183 }
00184 else ++it;
00185 }
00186 }
00187
00188
00189 void KMAcctCachedImap::slotCheckQueuedFolders()
00190 {
00191 mMailCheckFolders.clear();
00192 mMailCheckFolders.append( mFoldersQueuedForChecking.front() );
00193 mFoldersQueuedForChecking.pop_front();
00194 if ( mFoldersQueuedForChecking.isEmpty() )
00195 disconnect( this, SIGNAL( finishedCheck( bool, CheckStatus ) ),
00196 this, SLOT( slotCheckQueuedFolders() ) );
00197
00198 kmkernel->acctMgr()->singleCheckMail(this, true);
00199 mMailCheckFolders.clear();
00200 }
00201
00202 void KMAcctCachedImap::processNewMail( bool )
00203 {
00204 assert( mFolder );
00205
00206 if ( mMailCheckFolders.isEmpty() )
00207 processNewMail( mFolder, true );
00208 else {
00209 KMFolder* f = mMailCheckFolders.front();
00210 mMailCheckFolders.pop_front();
00211 processNewMail( static_cast<KMFolderCachedImap *>( f->storage() ), false );
00212 }
00213 }
00214
00215 void KMAcctCachedImap::processNewMail( KMFolderCachedImap* folder,
00216 bool recurse )
00217 {
00218 assert( folder );
00219
00220 mAutoExpunge = false;
00221 mCountLastUnread = 0;
00222 mUnreadBeforeCheck.clear();
00223
00224 mNoopTimer.stop();
00225
00226
00227 if ( folder == mFolder ) {
00228 QStringList nsToList = namespaces()[PersonalNS];
00229 QStringList otherNSToCheck = namespaces()[OtherUsersNS];
00230 otherNSToCheck += namespaces()[SharedNS];
00231 for ( QStringList::Iterator it = otherNSToCheck.begin();
00232 it != otherNSToCheck.end(); ++it ) {
00233 if ( (*it).isEmpty() ) {
00234
00235
00236 nsToList += *it;
00237 }
00238 }
00239 folder->setNamespacesToList( nsToList );
00240 }
00241
00242 Q_ASSERT( !mMailCheckProgressItem );
00243 mMailCheckProgressItem = KPIM::ProgressManager::createProgressItem(
00244 "MailCheck" + QString::number( id() ),
00245 folder->label(),
00246 QString(),
00247 true,
00248 useSSL() || useTLS() );
00249 connect( mMailCheckProgressItem, SIGNAL( progressItemCanceled( KPIM::ProgressItem* ) ),
00250 this, SLOT( slotProgressItemCanceled( KPIM::ProgressItem* ) ) );
00251
00252 folder->setAccount(this);
00253 connect(folder, SIGNAL(folderComplete(KMFolderCachedImap*, bool)),
00254 this, SLOT(postProcessNewMail(KMFolderCachedImap*, bool)));
00255 folder->serverSync( recurse );
00256 }
00257
00258 void KMAcctCachedImap::postProcessNewMail( KMFolderCachedImap* folder, bool )
00259 {
00260 mNoopTimer.start( 60000 );
00261 disconnect(folder, SIGNAL(folderComplete(KMFolderCachedImap*, bool)),
00262 this, SLOT(postProcessNewMail(KMFolderCachedImap*, bool)));
00263 mMailCheckProgressItem->setComplete();
00264 mMailCheckProgressItem = 0;
00265
00266 if ( folder == mFolder ) {
00267
00268
00269
00270
00271
00272
00273 #if 0 // this opens a race: delete a folder during a sync (after the sync checked that folder), and it'll be forgotten...
00274 mDeletedFolders.clear();
00275 #endif
00276 mPreviouslyDeletedFolders.clear();
00277 }
00278
00279 KMail::ImapAccountBase::postProcessNewMail();
00280 }
00281
00282 void KMAcctCachedImap::addUnreadMsgCount( const KMFolderCachedImap *folder,
00283 int countUnread )
00284 {
00285 if ( folder->imapPath() != "/INBOX/" ) {
00286
00287
00288 const QString folderId = folder->folder()->idString();
00289 int newInFolder = countUnread;
00290 if ( mUnreadBeforeCheck.contains( folderId ) )
00291 newInFolder -= mUnreadBeforeCheck[folderId];
00292 if ( newInFolder > 0 )
00293 addToNewInFolder( folderId, newInFolder );
00294 }
00295 mCountUnread += countUnread;
00296 }
00297
00298 void KMAcctCachedImap::addLastUnreadMsgCount( const KMFolderCachedImap *folder,
00299 int countLastUnread )
00300 {
00301 mUnreadBeforeCheck[folder->folder()->idString()] = countLastUnread;
00302 mCountLastUnread += countLastUnread;
00303 }
00304
00305
00306
00307
00308
00309
00310
00311 void KMAcctCachedImap::readConfig( KConfigGroup & config ) {
00312 ImapAccountBase::readConfig( config );
00313
00314 mPreviouslyDeletedFolders = config.readEntry( "deleted-folders", QStringList() );
00315 mDeletedFolders.clear();
00316 const QStringList oldPaths = config.readEntry( "renamed-folders-paths", QStringList() );
00317 const QStringList newNames = config.readEntry( "renamed-folders-names", QStringList() );
00318 QStringList::const_iterator it = oldPaths.begin();
00319 QStringList::const_iterator nameit = newNames.begin();
00320 for( ; it != oldPaths.end() && nameit != newNames.end(); ++it, ++nameit ) {
00321 addRenamedFolder( *it, QString(), *nameit );
00322 }
00323 mGroupwareType = (GroupwareType)config.readEntry( "groupwareType", (int)GroupwareKolab );
00324 }
00325
00326 void KMAcctCachedImap::writeConfig( KConfigGroup & config ) {
00327 ImapAccountBase::writeConfig( config );
00328 config.writeEntry( "deleted-folders", mDeletedFolders + mPreviouslyDeletedFolders );
00329 config.writeEntry( "renamed-folders-paths", mRenamedFolders.keys() );
00330 const QList<RenamedFolder> values = mRenamedFolders.values();
00331 QStringList lstNames;
00332 QList<RenamedFolder>::const_iterator it = values.begin();
00333 for ( ; it != values.end() ; ++it )
00334 lstNames.append( (*it).mNewName );
00335 config.writeEntry( "renamed-folders-names", lstNames );
00336 config.writeEntry( "groupwareType", (int)mGroupwareType );
00337 }
00338
00339 void KMAcctCachedImap::invalidateIMAPFolders()
00340 {
00341 invalidateIMAPFolders( mFolder );
00342 }
00343
00344 void KMAcctCachedImap::invalidateIMAPFolders( KMFolderCachedImap* folder )
00345 {
00346 if( !folder || !folder->folder() )
00347 return;
00348
00349 folder->setAccount(this);
00350
00351 QStringList strList;
00352 QList<QPointer<KMFolder> > folderList;
00353 kmkernel->dimapFolderMgr()->createFolderList( &strList, &folderList,
00354 folder->folder()->child(), QString(),
00355 false );
00356 QList<QPointer<KMFolder> >::Iterator it;
00357 mCountLastUnread = 0;
00358 mUnreadBeforeCheck.clear();
00359
00360 for( it = folderList.begin(); it != folderList.end(); ++it ) {
00361 KMFolder *f = *it;
00362 if( f && f->folderType() == KMFolderTypeCachedImap ) {
00363 KMFolderCachedImap *cfolder = static_cast<KMFolderCachedImap*>(f->storage());
00364
00365 cfolder->setUidValidity("INVALID");
00366 cfolder->writeUidCache();
00367 processNewMailSingleFolder( f );
00368 }
00369 }
00370 folder->setUidValidity("INVALID");
00371 folder->writeUidCache();
00372
00373 processNewMailSingleFolder( folder->folder() );
00374 }
00375
00376
00377 void KMAcctCachedImap::addDeletedFolder( KMFolder* folder )
00378 {
00379 if ( !folder || folder->folderType() != KMFolderTypeCachedImap )
00380 return;
00381 KMFolderCachedImap* storage = static_cast<KMFolderCachedImap*>(folder->storage());
00382 addDeletedFolder( storage->imapPath() );
00383 kDebug(5006) << storage->imapPath();
00384
00385
00386 if( folder->child() ) {
00387 QList<KMFolderNode*>::const_iterator it;
00388 for ( it = folder->child()->constBegin();
00389 it != folder->child()->constEnd();
00390 ++it ) {
00391 KMFolderNode *node = (*it);
00392 if( node && !node->isDir() ) {
00393 addDeletedFolder( static_cast<KMFolder*>( node ) );
00394 }
00395 }
00396 }
00397 }
00398
00399 void KMAcctCachedImap::addDeletedFolder( const QString& imapPath )
00400 {
00401 mDeletedFolders << imapPath;
00402 }
00403
00404 QStringList KMAcctCachedImap::deletedFolderPaths( const QString& subFolderPath ) const
00405 {
00406 QStringList lst;
00407 for ( QStringList::const_iterator it = mDeletedFolders.begin(); it != mDeletedFolders.end(); ++it ) {
00408 if ( (*it).startsWith( subFolderPath ) )
00409
00410 lst.prepend( *it );
00411 }
00412 for ( QStringList::const_iterator it = mPreviouslyDeletedFolders.begin(); it != mPreviouslyDeletedFolders.end(); ++it ) {
00413 if ( (*it).startsWith( subFolderPath ) )
00414 lst.prepend( *it );
00415 }
00416 kDebug(5006) << "For" << subFolderPath <<" returning:" << lst;
00417 Q_ASSERT( !lst.isEmpty() );
00418 return lst;
00419 }
00420
00421 bool KMAcctCachedImap::isDeletedFolder( const QString& subFolderPath ) const
00422 {
00423 return mDeletedFolders.contains( subFolderPath ) ;
00424 }
00425
00426 bool KMAcctCachedImap::isPreviouslyDeletedFolder( const QString& subFolderPath ) const
00427 {
00428 return mPreviouslyDeletedFolders.contains( subFolderPath ) ;
00429 }
00430
00431 void KMAcctCachedImap::removeDeletedFolder( const QString& subFolderPath )
00432 {
00433 mDeletedFolders.removeAll( subFolderPath );
00434 mPreviouslyDeletedFolders.removeAll( subFolderPath );
00435 }
00436
00437 void KMAcctCachedImap::addRenamedFolder( const QString& subFolderPath, const QString& oldLabel, const QString& newName )
00438 {
00439 mRenamedFolders.insert( subFolderPath, RenamedFolder( oldLabel, newName ) );
00440 }
00441
00442 void KMAcctCachedImap::removeRenamedFolder( const QString& subFolderPath )
00443 {
00444 mRenamedFolders.remove( subFolderPath );
00445 }
00446
00447 void KMAcctCachedImap::slotProgressItemCanceled( ProgressItem* )
00448 {
00449 bool abortConnection = !mSlaveConnected;
00450 killAllJobs( abortConnection );
00451 if ( abortConnection ) {
00452
00453 emit connectionResult( KIO::ERR_USER_CANCELED, QString() );
00454 }
00455 }
00456
00457 FolderStorage* KMAcctCachedImap::rootFolder() const
00458 {
00459 return mFolder;
00460 }
00461
00462
00463 QString KMAcctCachedImap::renamedFolder( const QString& imapPath ) const
00464 {
00465 QMap<QString, RenamedFolder>::ConstIterator renit = mRenamedFolders.find( imapPath );
00466 if ( renit != mRenamedFolders.end() )
00467 return (*renit).mNewName;
00468 return QString();
00469 }
00470
00471 #include "kmacctcachedimap.moc"