00001
00032 #ifdef HAVE_CONFIG_H
00033 #include <config.h>
00034 #endif
00035
00036 #include <errno.h>
00037
00038 #include <qvaluevector.h>
00039
00040 #include "kmkernel.h"
00041 #include "kmfoldercachedimap.h"
00042 #include "undostack.h"
00043 #include "kmfoldermgr.h"
00044 #include "kmacctcachedimap.h"
00045 #include "accountmanager.h"
00046 using KMail::AccountManager;
00047 #include "kmailicalifaceimpl.h"
00048 #include "kmfolder.h"
00049 #include "kmglobal.h"
00050 #include "acljobs.h"
00051 #include "broadcaststatus.h"
00052 using KPIM::BroadcastStatus;
00053 #include "progressmanager.h"
00054
00055 using KMail::CachedImapJob;
00056 #include "imapaccountbase.h"
00057 using KMail::ImapAccountBase;
00058 #include "listjob.h"
00059 using KMail::ListJob;
00060
00061 #include "kmfolderseldlg.h"
00062 #include "kmcommands.h"
00063 #include "kmmainwidget.h"
00064
00065 #include <kapplication.h>
00066 #include <kmessagebox.h>
00067 #include <klocale.h>
00068 #include <kdebug.h>
00069 #include <kconfig.h>
00070 #include <kio/global.h>
00071 #include <kio/scheduler.h>
00072 #include <qbuffer.h>
00073 #include <qbuttongroup.h>
00074 #include <qcombobox.h>
00075 #include <qfile.h>
00076 #include <qhbox.h>
00077 #include <qlabel.h>
00078 #include <qlayout.h>
00079 #include <qradiobutton.h>
00080 #include <qvaluelist.h>
00081 #include "annotationjobs.h"
00082 #include "quotajobs.h"
00083 using namespace KMail;
00084 #include <globalsettings.h>
00085
00086 #define UIDCACHE_VERSION 1
00087 #define MAIL_LOSS_DEBUGGING 0
00088
00089 static QString incidencesForToString( KMFolderCachedImap::IncidencesFor r ) {
00090 switch (r) {
00091 case KMFolderCachedImap::IncForNobody: return "nobody";
00092 case KMFolderCachedImap::IncForAdmins: return "admins";
00093 case KMFolderCachedImap::IncForReaders: return "readers";
00094 }
00095 return QString::null;
00096 }
00097
00098 static KMFolderCachedImap::IncidencesFor incidencesForFromString( const QString& str ) {
00099 if ( str == "nobody" ) return KMFolderCachedImap::IncForNobody;
00100 if ( str == "admins" ) return KMFolderCachedImap::IncForAdmins;
00101 if ( str == "readers" ) return KMFolderCachedImap::IncForReaders;
00102 return KMFolderCachedImap::IncForAdmins;
00103 }
00104
00105 DImapTroubleShootDialog::DImapTroubleShootDialog( QWidget* parent,
00106 const char* name )
00107 : KDialogBase( Plain, i18n( "Troubleshooting IMAP Cache" ),
00108 Ok | Cancel, Cancel, parent, name, true ),
00109 rc( None )
00110 {
00111 QFrame* page = plainPage();
00112 QVBoxLayout *topLayout = new QVBoxLayout( page, 0 );
00113
00114 QString txt = i18n( "<p><b>Troubleshooting the IMAP cache.</b></p>"
00115 "<p>If you have problems with synchronizing an IMAP "
00116 "folder, you should first try rebuilding the index "
00117 "file. This will take some time to rebuild, but will "
00118 "not cause any problems.</p><p>If that is not enough, "
00119 "you can try refreshing the IMAP cache. If you do this, "
00120 "you will loose all your local changes for this folder "
00121 "and all its subfolders.</p>",
00122 "<p><b>Troubleshooting the IMAP cache.</b></p>"
00123 "<p>If you have problems with synchronizing an IMAP "
00124 "folder, you should first try rebuilding the index "
00125 "file. This will take some time to rebuild, but will "
00126 "not cause any problems.</p><p>If that is not enough, "
00127 "you can try refreshing the IMAP cache. If you do this, "
00128 "you will lose all your local changes for this folder "
00129 "and all its subfolders.</p>" );
00130 topLayout->addWidget( new QLabel( txt, page ) );
00131
00132 QButtonGroup *group = new QButtonGroup( 0 );
00133
00134 mIndexButton = new QRadioButton( page );
00135 mIndexButton->setText( i18n( "Rebuild &Index" ) );
00136 group->insert( mIndexButton );
00137 topLayout->addWidget( mIndexButton );
00138
00139 QHBox *hbox = new QHBox( page );
00140 QLabel *scopeLabel = new QLabel( i18n( "Scope:" ), hbox );
00141 scopeLabel->setEnabled( false );
00142 mIndexScope = new QComboBox( hbox );
00143 mIndexScope->insertItem( i18n( "Only current folder" ) );
00144 mIndexScope->insertItem( i18n( "Current folder and all subfolders" ) );
00145 mIndexScope->insertItem( i18n( "All folders of this account" ) );
00146 mIndexScope->setEnabled( false );
00147 topLayout->addWidget( hbox );
00148
00149 mCacheButton = new QRadioButton( page );
00150 mCacheButton->setText( i18n( "Refresh &Cache" ) );
00151 group->insert( mCacheButton );
00152 topLayout->addWidget( mCacheButton );
00153
00154 enableButtonSeparator( true );
00155
00156 connect ( mIndexButton, SIGNAL(toggled(bool)), mIndexScope, SLOT(setEnabled(bool)) );
00157 connect ( mIndexButton, SIGNAL(toggled(bool)), scopeLabel, SLOT(setEnabled(bool)) );
00158
00159 connect( this, SIGNAL( okClicked () ), this, SLOT( slotDone() ) );
00160 }
00161
00162 int DImapTroubleShootDialog::run()
00163 {
00164 DImapTroubleShootDialog d;
00165 d.exec();
00166 return d.rc;
00167 }
00168
00169 void DImapTroubleShootDialog::slotDone()
00170 {
00171 rc = None;
00172 if ( mIndexButton->isOn() )
00173 rc = mIndexScope->currentItem();
00174 else if ( mCacheButton->isOn() )
00175 rc = RefreshCache;
00176 done( Ok );
00177 }
00178
00179 KMFolderCachedImap::KMFolderCachedImap( KMFolder* folder, const char* aName )
00180 : KMFolderMaildir( folder, aName ),
00181 mSyncState( SYNC_STATE_INITIAL ), mContentState( imapNoInformation ),
00182 mSubfolderState( imapNoInformation ),
00183 mIncidencesFor( IncForAdmins ),
00184 mSharedSeenFlags( false ),
00185 mIsSelected( false ),
00186 mCheckFlags( true ), mReadOnly( false ), mAccount( NULL ), uidMapDirty( true ),
00187 uidWriteTimer( -1 ), mLastUid( 0 ), mTentativeHighestUid( 0 ),
00188 mFoundAnIMAPDigest( false ),
00189 mUserRights( 0 ), mOldUserRights( 0 ), mSilentUpload( false ),
00190
00191 mFolderRemoved( false ),
00192 mRecurse( true ),
00193 mAnnotationFolderTypeChanged( false ),
00194 mIncidencesForChanged( false ),
00195 mSharedSeenFlagsChanged( false ),
00196 mStatusChangedLocally( false ),
00197 mPersonalNamespacesCheckDone( true ),
00198 mQuotaInfo(), mAlarmsBlocked( false ),
00199 mRescueCommandCount( 0 ),
00200 mPermanentFlags( 31 )
00201 {
00202 setUidValidity("");
00203
00204 if ( readUidCache() == -1 ) {
00205 if ( QFile::exists( uidCacheLocation() ) ) {
00206 KMessageBox::error( 0,
00207 i18n( "The UID cache file for folder %1 could not be read. There "
00208 "could be a problem with file system permission, or it is corrupted."
00209 ).arg( folder->prettyURL() ) );
00210
00211
00212 unlink( QFile::encodeName( uidCacheLocation() ) );
00213 }
00214 }
00215
00216 mProgress = 0;
00217 }
00218
00219 KMFolderCachedImap::~KMFolderCachedImap()
00220 {
00221 if (kmkernel->undoStack()) kmkernel->undoStack()->folderDestroyed( folder() );
00222 writeConfig();
00223 }
00224
00225 void KMFolderCachedImap::reallyDoClose( const char* owner )
00226 {
00227 if( !mFolderRemoved ) {
00228 writeUidCache();
00229 }
00230 KMFolderMaildir::reallyDoClose( owner );
00231 }
00232
00233 void KMFolderCachedImap::initializeFrom( KMFolderCachedImap* parent )
00234 {
00235 setAccount( parent->account() );
00236
00237
00238 mAccount->removeDeletedFolder( imapPath() );
00239 setUserRights( parent->userRights() );
00240 }
00241
00242 void KMFolderCachedImap::readConfig()
00243 {
00244 KConfig* config = KMKernel::config();
00245 KConfigGroupSaver saver( config, "Folder-" + folder()->idString() );
00246 if( mImapPath.isEmpty() ) mImapPath = config->readEntry( "ImapPath" );
00247 if( QString( name() ).upper() == "INBOX" && mImapPath == "/INBOX/" )
00248 {
00249 folder()->setLabel( i18n( "inbox" ) );
00250
00251 folder()->setSystemFolder( true );
00252 }
00253 mNoContent = config->readBoolEntry( "NoContent", false );
00254 mReadOnly = config->readBoolEntry( "ReadOnly", false );
00255 if ( !config->readEntry( "FolderAttributes" ).isEmpty() )
00256 mFolderAttributes = config->readEntry( "FolderAttributes" );
00257
00258 if ( mAnnotationFolderType != "FROMSERVER" ) {
00259 mAnnotationFolderType = config->readEntry( "Annotation-FolderType" );
00260
00261 if ( !mAnnotationFolderType.isEmpty() && !mAnnotationFolderType.startsWith( "mail" ) )
00262 kmkernel->iCalIface().setStorageFormat( folder(), KMailICalIfaceImpl::StorageXML );
00263
00264
00265 }
00266 mIncidencesFor = incidencesForFromString( config->readEntry( "IncidencesFor" ) );
00267 mAlarmsBlocked = config->readBoolEntry( "AlarmsBlocked", false );
00268
00269
00270 mSharedSeenFlags = config->readBoolEntry( "SharedSeenFlags", false );
00271
00272 mUserRights = config->readNumEntry( "UserRights", 0 );
00273 mOldUserRights = mUserRights;
00274
00275 int storageQuotaUsage = config->readNumEntry( "StorageQuotaUsage", -1 );
00276 int storageQuotaLimit = config->readNumEntry( "StorageQuotaLimit", -1 );
00277 QString storageQuotaRoot = config->readEntry( "StorageQuotaRoot", QString::null );
00278 if ( !storageQuotaRoot.isNull() ) {
00279 mQuotaInfo.setName( "STORAGE" );
00280 mQuotaInfo.setRoot( storageQuotaRoot );
00281
00282 if ( storageQuotaUsage > -1 )
00283 mQuotaInfo.setCurrent( storageQuotaUsage );
00284 if ( storageQuotaLimit > -1 )
00285 mQuotaInfo.setMax( storageQuotaLimit );
00286 }
00287
00288 KMFolderMaildir::readConfig();
00289
00290 mStatusChangedLocally =
00291 config->readBoolEntry( "StatusChangedLocally", false );
00292 QStringList uidsChanged = config->readListEntry( "UIDStatusChangedLocally" );
00293 for ( QStringList::iterator it = uidsChanged.begin(); it != uidsChanged.end(); it++ ) {
00294 mUIDsOfLocallyChangedStatuses.append( ( *it ).toUInt() );
00295 }
00296
00297 mAnnotationFolderTypeChanged = config->readBoolEntry( "AnnotationFolderTypeChanged", false );
00298 mIncidencesForChanged = config->readBoolEntry( "IncidencesForChanged", false );
00299 mSharedSeenFlagsChanged = config->readBoolEntry( "SharedSeenFlagsChanged", false );
00300
00301 if ( mImapPath.isEmpty() ) {
00302 mImapPathCreation = config->readEntry("ImapPathCreation");
00303 }
00304
00305 QStringList delUids = config->readListEntry( "UIDSDeletedSinceLastSync" );
00306 #if MAIL_LOSS_DEBUGGING
00307 kdDebug( 5006 ) << "READING IN UIDSDeletedSinceLastSync: " << folder()->prettyURL() << endl << uids << endl;
00308 #endif
00309 for ( QStringList::iterator it = delUids.begin(); it != delUids.end(); it++ ) {
00310 mDeletedUIDsSinceLastSync.insert( (*it).toULong(), 0);
00311 }
00312 }
00313
00314 void KMFolderCachedImap::writeConfig()
00315 {
00316
00317
00318 if ( mFolderRemoved )
00319 return;
00320
00321 KConfigGroup configGroup( KMKernel::config(), "Folder-" + folder()->idString() );
00322 configGroup.writeEntry( "ImapPath", mImapPath );
00323 configGroup.writeEntry( "NoContent", mNoContent );
00324 configGroup.writeEntry( "ReadOnly", mReadOnly );
00325 configGroup.writeEntry( "FolderAttributes", mFolderAttributes );
00326
00327
00328 configGroup.writeEntry( "StatusChangedLocally", false );
00329 QStringList uidsToWrite;
00330 for( QValueList<ulong>::iterator it = mUIDsOfLocallyChangedStatuses.begin();
00331 it != mUIDsOfLocallyChangedStatuses.end(); it++ ) {
00332 uidsToWrite.append( QString::number( (*it) ) );
00333 }
00334 configGroup.writeEntry( "UIDStatusChangedLocally", uidsToWrite );
00335 if ( !mImapPathCreation.isEmpty() ) {
00336 if ( mImapPath.isEmpty() ) {
00337 configGroup.writeEntry( "ImapPathCreation", mImapPathCreation );
00338 } else {
00339 configGroup.deleteEntry( "ImapPathCreation" );
00340 }
00341 }
00342 if ( !mDeletedUIDsSinceLastSync.isEmpty() ) {
00343 QValueList<ulong> uids = mDeletedUIDsSinceLastSync.keys();
00344 QStringList uidstrings;
00345 for( QValueList<ulong>::iterator it = uids.begin(); it != uids.end(); it++ ) {
00346 uidstrings.append( QString::number( (*it) ) );
00347 }
00348 configGroup.writeEntry( "UIDSDeletedSinceLastSync", uidstrings );
00349 #if MAIL_LOSS_DEBUGGING
00350 kdDebug( 5006 ) << "WRITING OUT UIDSDeletedSinceLastSync in: " << folder( )->prettyURL( ) << endl << uidstrings << endl;
00351 #endif
00352 } else {
00353 configGroup.deleteEntry( "UIDSDeletedSinceLastSync" );
00354 }
00355 writeConfigKeysWhichShouldNotGetOverwrittenByReadConfig();
00356 KMFolderMaildir::writeConfig();
00357 }
00358
00359 void KMFolderCachedImap::writeConfigKeysWhichShouldNotGetOverwrittenByReadConfig()
00360 {
00361 KConfigGroup configGroup( KMKernel::config(), "Folder-" + folder()->idString() );
00362 if ( !folder()->noContent() )
00363 {
00364 configGroup.writeEntry( "AnnotationFolderTypeChanged", mAnnotationFolderTypeChanged );
00365 configGroup.writeEntry( "Annotation-FolderType", mAnnotationFolderType );
00366 configGroup.writeEntry( "IncidencesForChanged", mIncidencesForChanged );
00367 configGroup.writeEntry( "IncidencesFor", incidencesForToString( mIncidencesFor ) );
00368 configGroup.writeEntry( "AlarmsBlocked", mAlarmsBlocked );
00369 configGroup.writeEntry( "SharedSeenFlags", mSharedSeenFlags );
00370 configGroup.writeEntry( "SharedSeenFlagsChanged", mSharedSeenFlagsChanged );
00371 configGroup.writeEntry( "UserRights", mUserRights );
00372
00373 configGroup.deleteEntry( "StorageQuotaUsage");
00374 configGroup.deleteEntry( "StorageQuotaRoot");
00375 configGroup.deleteEntry( "StorageQuotaLimit");
00376
00377 if ( mQuotaInfo.isValid() ) {
00378 if ( mQuotaInfo.current().isValid() ) {
00379 configGroup.writeEntry( "StorageQuotaUsage", mQuotaInfo.current().toInt() );
00380 }
00381 if ( mQuotaInfo.max().isValid() ) {
00382 configGroup.writeEntry( "StorageQuotaLimit", mQuotaInfo.max().toInt() );
00383 }
00384 configGroup.writeEntry( "StorageQuotaRoot", mQuotaInfo.root() );
00385 }
00386 }
00387 }
00388
00389 int KMFolderCachedImap::create()
00390 {
00391 int rc = KMFolderMaildir::create();
00392
00393 readConfig();
00394 mUnreadMsgs = -1;
00395 return rc;
00396 }
00397
00398 void KMFolderCachedImap::remove()
00399 {
00400 mFolderRemoved = true;
00401
00402 QString part1 = folder()->path() + "/." + dotEscape(name());
00403 QString uidCacheFile = part1 + ".uidcache";
00404
00405
00406 if( QFile::exists(uidCacheFile) )
00407 unlink( QFile::encodeName( uidCacheFile ) );
00408
00409 FolderStorage::remove();
00410 }
00411
00412 QString KMFolderCachedImap::uidCacheLocation() const
00413 {
00414 QString sLocation(folder()->path());
00415 if (!sLocation.isEmpty()) sLocation += '/';
00416 return sLocation + '.' + dotEscape(fileName()) + ".uidcache";
00417 }
00418
00419 int KMFolderCachedImap::readUidCache()
00420 {
00421 QFile uidcache( uidCacheLocation() );
00422 if( uidcache.open( IO_ReadOnly ) ) {
00423 char buf[1024];
00424 int len = uidcache.readLine( buf, sizeof(buf) );
00425 if( len > 0 ) {
00426 int cacheVersion;
00427 sscanf( buf, "# KMail-UidCache V%d\n", &cacheVersion );
00428 if( cacheVersion == UIDCACHE_VERSION ) {
00429 len = uidcache.readLine( buf, sizeof(buf) );
00430 if( len > 0 ) {
00431 setUidValidity( QString::fromLocal8Bit(buf).stripWhiteSpace() );
00432 len = uidcache.readLine( buf, sizeof(buf) );
00433 if( len > 0 ) {
00434 #if MAIL_LOSS_DEBUGGING
00435 kdDebug(5006) << "Reading in last uid from cache: " << QString::fromLocal8Bit(buf).stripWhiteSpace() << " in " << folder()->prettyURL() << endl;
00436 #endif
00437
00438 setLastUid( QString::fromLocal8Bit(buf).stripWhiteSpace().toULong() );
00439 return 0;
00440 }
00441 }
00442 }
00443 }
00444 }
00445 return -1;
00446 }
00447
00448 int KMFolderCachedImap::writeUidCache()
00449 {
00450 if( uidValidity().isEmpty() || uidValidity() == "INVALID" ) {
00451
00452 if( QFile::exists( uidCacheLocation() ) )
00453 return unlink( QFile::encodeName( uidCacheLocation() ) );
00454 return 0;
00455 }
00456 #if MAIL_LOSS_DEBUGGING
00457 kdDebug(5006) << "Writing out UID cache lastuid: " << lastUid() << " in: " << folder()->prettyURL() << endl;
00458 #endif
00459 QFile uidcache( uidCacheLocation() );
00460 if( uidcache.open( IO_WriteOnly ) ) {
00461 QTextStream str( &uidcache );
00462 str << "# KMail-UidCache V" << UIDCACHE_VERSION << endl;
00463 str << uidValidity() << endl;
00464 str << lastUid() << endl;
00465 uidcache.flush();
00466 if ( uidcache.status() == IO_Ok ) {
00467 fsync( uidcache.handle() );
00468 uidcache.close();
00469 if ( uidcache.status() == IO_Ok )
00470 return 0;
00471 }
00472 }
00473 KMessageBox::error( 0,
00474 i18n( "The UID cache file for folder %1 could not be written. There "
00475 "could be a problem with file system permission." ).arg( folder()->prettyURL() ) );
00476
00477 return -1;
00478 }
00479
00480 void KMFolderCachedImap::reloadUidMap()
00481 {
00482
00483 uidMap.clear();
00484 open("reloadUdi");
00485 for( int i = 0; i < count(); ++i ) {
00486 KMMsgBase *msg = getMsgBase( i );
00487 if( !msg ) continue;
00488 ulong uid = msg->UID();
00489
00490 uidMap.insert( uid, i );
00491 }
00492 close("reloadUdi");
00493 uidMapDirty = false;
00494 }
00495
00496
00497 KMMessage* KMFolderCachedImap::take(int idx)
00498 {
00499 uidMapDirty = true;
00500 rememberDeletion( idx );
00501 return KMFolderMaildir::take(idx);
00502 }
00503
00504
00505 int KMFolderCachedImap::addMsgInternal( KMMessage* msg, bool newMail,
00506 int* index_return )
00507 {
00508
00509 ulong uid = msg->UID();
00510 if( uid != 0 ) {
00511 uidMapDirty = true;
00512 }
00513
00514 KMFolderOpener openThis(folder(), "KMFolderCachedImap::addMsgInternal");
00515 int rc = openThis.openResult();
00516 if ( rc ) {
00517 kdDebug(5006) << k_funcinfo << "open: " << rc << " of folder: " << label() << endl;
00518 return rc;
00519 }
00520
00521
00522 rc = KMFolderMaildir::addMsg(msg, index_return);
00523
00524 if( newMail && ( imapPath() == "/INBOX/" ||
00525 ( (userRights() <= 0 || userRights() & ACLJobs::Administer)
00526 && (contentsType() == ContentsTypeMail || GlobalSettings::self()->filterGroupwareFolders()) ) ) )
00527 {
00528
00529 bool filter = false;
00530 if ( GlobalSettings::filterSourceFolders().isEmpty() ) {
00531 if ( imapPath() == "/INBOX/" )
00532 filter = true;
00533 } else {
00534 if ( GlobalSettings::filterSourceFolders().contains( folder()->id() ) )
00535 filter = true;
00536 }
00537 if ( filter )
00538 mAccount->processNewMsg( msg );
00539 }
00540
00541 return rc;
00542 }
00543
00544
00545 int KMFolderCachedImap::addMsg(KMMessage* msg, int* index_return)
00546 {
00547 if ( !canAddMsgNow( msg, index_return ) ) return 0;
00548
00549 int rc = KMFolderMaildir::addMsgInternal(msg, index_return, true );
00550 return rc;
00551 }
00552
00553 void KMFolderCachedImap::rememberDeletion( int idx )
00554 {
00555 KMMsgBase *msg = getMsgBase( idx );
00556 assert(msg);
00557 long uid = msg->UID();
00558 assert(uid>=0);
00559 mDeletedUIDsSinceLastSync.insert(uid, 0);
00560 kdDebug(5006) << "Explicit delete of UID " << uid << " at index: " << idx << " in " << folder()->prettyURL() << endl;
00561 }
00562
00563
00564 void KMFolderCachedImap::removeMsg(int idx, bool imapQuiet)
00565 {
00566 uidMapDirty = true;
00567 rememberDeletion( idx );
00568
00569 KMFolderMaildir::removeMsg(idx,imapQuiet);
00570 }
00571
00572 bool KMFolderCachedImap::canRemoveFolder() const {
00573
00574 if( folder() && folder()->child() && folder()->child()->count() > 0 )
00575 return false;
00576
00577 #if 0
00578
00579 return KMFolderMaildir::canRemoveFolder();
00580 #endif
00581 return true;
00582 }
00583
00584
00585 int KMFolderCachedImap::rename( const QString& aName,
00586 KMFolderDir* )
00587 {
00588 QString oldName = mAccount->renamedFolder( imapPath() );
00589 if ( oldName.isEmpty() ) oldName = name();
00590 if ( aName == oldName )
00591
00592 return 0;
00593
00594 if( account() == 0 || imapPath().isEmpty() ) {
00595 QString err = i18n("You must synchronize with the server before renaming IMAP folders.");
00596 KMessageBox::error( 0, err );
00597 return -1;
00598 }
00599
00600
00601
00602
00603
00604
00605 if ( name() != aName )
00606 mAccount->addRenamedFolder( imapPath(), folder()->label(), aName );
00607 else
00608 mAccount->removeRenamedFolder( imapPath() );
00609
00610 folder()->setLabel( aName );
00611 emit nameChanged();
00612
00613 return 0;
00614 }
00615
00616 KMFolder* KMFolderCachedImap::trashFolder() const
00617 {
00618 QString trashStr = account()->trash();
00619 return kmkernel->dimapFolderMgr()->findIdString( trashStr );
00620 }
00621
00622 void KMFolderCachedImap::setLastUid( ulong uid )
00623 {
00624 #if MAIL_LOSS_DEBUGGING
00625 kdDebug(5006) << "Setting mLastUid to: " << uid << " in " << folder()->prettyURL() << endl;
00626 #endif
00627 mLastUid = uid;
00628 if( uidWriteTimer == -1 )
00629
00630 uidWriteTimer = startTimer( 60000 );
00631 }
00632
00633 void KMFolderCachedImap::timerEvent( QTimerEvent* )
00634 {
00635 killTimer( uidWriteTimer );
00636 uidWriteTimer = -1;
00637 if ( writeUidCache() == -1 )
00638 unlink( QFile::encodeName( uidCacheLocation() ) );
00639 }
00640
00641 ulong KMFolderCachedImap::lastUid()
00642 {
00643 return mLastUid;
00644 }
00645
00646 KMMsgBase* KMFolderCachedImap::findByUID( ulong uid )
00647 {
00648 bool mapReloaded = false;
00649 if( uidMapDirty ) {
00650 reloadUidMap();
00651 mapReloaded = true;
00652 }
00653
00654 QMap<ulong,int>::Iterator it = uidMap.find( uid );
00655 if( it != uidMap.end() ) {
00656 KMMsgBase *msg = getMsgBase( *it );
00657 #if MAIL_LOSS_DEBUGGING
00658 kdDebug(5006) << "Folder: " << folder()->prettyURL() << endl;
00659 kdDebug(5006) << "UID " << uid << " is supposed to be in the map" << endl;
00660 kdDebug(5006) << "UID's index is to be " << *it << endl;
00661 kdDebug(5006) << "There is a message there? " << (msg != 0) << endl;
00662 if ( msg ) {
00663 kdDebug(5006) << "Its UID is: " << msg->UID() << endl;
00664 }
00665 #endif
00666
00667 if( msg && msg->UID() == uid )
00668 return msg;
00669 kdDebug(5006) << "########## Didn't find uid: " << uid << "in cache athough it's supposed to be there!" << endl;
00670 } else {
00671 #if MAIL_LOSS_DEBUGGING
00672 kdDebug(5006) << "Didn't find uid: " << uid << "in cache!" << endl;
00673 #endif
00674 }
00675
00676
00677
00678 return 0;
00679
00680 reloadUidMap();
00681 it = uidMap.find( uid );
00682 if( it != uidMap.end() )
00683
00684 return getMsgBase( *it );
00685 #if MAIL_LOSS_DEBUGGING
00686 else
00687 kdDebug(5006) << "Reloaded, but stil didn't find uid: " << uid << endl;
00688 #endif
00689
00690 return 0;
00691 }
00692
00693
00694
00695 KMAcctCachedImap *KMFolderCachedImap::account() const
00696 {
00697 if( (KMAcctCachedImap *)mAccount == 0 && kmkernel && kmkernel->acctMgr() ) {
00698
00699 mAccount = static_cast<KMAcctCachedImap *>( kmkernel->acctMgr()->findByName( name() ) );
00700 }
00701
00702 return mAccount;
00703 }
00704
00705 void KMFolderCachedImap::slotTroubleshoot()
00706 {
00707 const int rc = DImapTroubleShootDialog::run();
00708
00709 if( rc == DImapTroubleShootDialog::RefreshCache ) {
00710
00711 if( !account() ) {
00712 KMessageBox::sorry( 0, i18n("No account setup for this folder.\n"
00713 "Please try running a sync before this.") );
00714 return;
00715 }
00716 QString str = i18n("Are you sure you want to refresh the IMAP cache of "
00717 "the folder %1 and all its subfolders?\nThis will "
00718 "remove all changes you have done locally to your "
00719 "folders.").arg( label() );
00720 QString s1 = i18n("Refresh IMAP Cache");
00721 QString s2 = i18n("&Refresh");
00722 if( KMessageBox::warningContinueCancel( 0, str, s1, s2 ) ==
00723 KMessageBox::Continue )
00724 account()->invalidateIMAPFolders( this );
00725 } else {
00726
00727 switch ( rc ) {
00728 case DImapTroubleShootDialog::ReindexAll:
00729 {
00730 KMFolderCachedImap *rootStorage = dynamic_cast<KMFolderCachedImap*>( account()->rootFolder() );
00731 if ( rootStorage )
00732 rootStorage->createIndexFromContentsRecursive();
00733 break;
00734 }
00735 case DImapTroubleShootDialog::ReindexCurrent:
00736 createIndexFromContents();
00737 break;
00738 case DImapTroubleShootDialog::ReindexRecursive:
00739 createIndexFromContentsRecursive();
00740 break;
00741 default:
00742 return;
00743 }
00744 KMessageBox::information( 0, i18n( "The index of this folder has been "
00745 "recreated." ) );
00746 writeIndex();
00747 kmkernel->getKMMainWidget()->folderSelected();
00748 }
00749 }
00750
00751 void KMFolderCachedImap::serverSync( bool recurse )
00752 {
00753 if( mSyncState != SYNC_STATE_INITIAL ) {
00754 if( KMessageBox::warningYesNo( 0, i18n("Folder %1 is not in initial sync state (state was %2). Do you want to reset it to initial sync state and sync anyway?" ).arg( imapPath() ).arg( mSyncState ), QString::null, i18n("Reset && Sync"), KStdGuiItem::cancel() ) == KMessageBox::Yes ) {
00755 mSyncState = SYNC_STATE_INITIAL;
00756 } else return;
00757 }
00758
00759 mRecurse = recurse;
00760 assert( account() );
00761
00762 ProgressItem *progressItem = mAccount->mailCheckProgressItem();
00763 if ( progressItem ) {
00764 progressItem->reset();
00765 progressItem->setTotalItems( 100 );
00766 }
00767 mProgress = 0;
00768
00769 #if 0
00770 if( mHoldSyncs ) {
00771
00772 account()->mailCheckProgressItem()->setProgress( 100 );
00773 mProgress = 100;
00774 newState( mProgress, i18n("Synchronization skipped"));
00775 mSyncState = SYNC_STATE_INITIAL;
00776 emit folderComplete( this, true );
00777 return;
00778 }
00779 #endif
00780 mTentativeHighestUid = 0;
00781
00782 serverSyncInternal();
00783 }
00784
00785 QString KMFolderCachedImap::state2String( int state ) const
00786 {
00787 switch( state ) {
00788 case SYNC_STATE_INITIAL: return "SYNC_STATE_INITIAL";
00789 case SYNC_STATE_GET_USERRIGHTS: return "SYNC_STATE_GET_USERRIGHTS";
00790 case SYNC_STATE_PUT_MESSAGES: return "SYNC_STATE_PUT_MESSAGES";
00791 case SYNC_STATE_UPLOAD_FLAGS: return "SYNC_STATE_UPLOAD_FLAGS";
00792 case SYNC_STATE_CREATE_SUBFOLDERS: return "SYNC_STATE_CREATE_SUBFOLDERS";
00793 case SYNC_STATE_LIST_SUBFOLDERS: return "SYNC_STATE_LIST_SUBFOLDERS";
00794 case SYNC_STATE_LIST_NAMESPACES: return "SYNC_STATE_LIST_NAMESPACES";
00795 case SYNC_STATE_LIST_SUBFOLDERS2: return "SYNC_STATE_LIST_SUBFOLDERS2";
00796 case SYNC_STATE_DELETE_SUBFOLDERS: return "SYNC_STATE_DELETE_SUBFOLDERS";
00797 case SYNC_STATE_LIST_MESSAGES: return "SYNC_STATE_LIST_MESSAGES";
00798 case SYNC_STATE_DELETE_MESSAGES: return "SYNC_STATE_DELETE_MESSAGES";
00799 case SYNC_STATE_GET_MESSAGES: return "SYNC_STATE_GET_MESSAGES";
00800 case SYNC_STATE_EXPUNGE_MESSAGES: return "SYNC_STATE_EXPUNGE_MESSAGES";
00801 case SYNC_STATE_HANDLE_INBOX: return "SYNC_STATE_HANDLE_INBOX";
00802 case SYNC_STATE_TEST_ANNOTATIONS: return "SYNC_STATE_TEST_ANNOTATIONS";
00803 case SYNC_STATE_GET_ANNOTATIONS: return "SYNC_STATE_GET_ANNOTATIONS";
00804 case SYNC_STATE_SET_ANNOTATIONS: return "SYNC_STATE_SET_ANNOTATIONS";
00805 case SYNC_STATE_GET_ACLS: return "SYNC_STATE_GET_ACLS";
00806 case SYNC_STATE_SET_ACLS: return "SYNC_STATE_SET_ACLS";
00807 case SYNC_STATE_GET_QUOTA: return "SYNC_STATE_GET_QUOTA";
00808 case SYNC_STATE_FIND_SUBFOLDERS: return "SYNC_STATE_FIND_SUBFOLDERS";
00809 case SYNC_STATE_SYNC_SUBFOLDERS: return "SYNC_STATE_SYNC_SUBFOLDERS";
00810 case SYNC_STATE_RENAME_FOLDER: return "SYNC_STATE_RENAME_FOLDER";
00811 case SYNC_STATE_CHECK_UIDVALIDITY: return "SYNC_STATE_CHECK_UIDVALIDITY";
00812 default: return "Unknown state";
00813 }
00814 }
00815
00816
00817
00818
00819
00820
00821
00822
00823
00824
00825
00826
00827
00828
00829
00830
00831
00832
00833
00834
00835
00836
00837
00838
00839
00840
00841
00842
00843
00844
00845
00846
00847 void KMFolderCachedImap::serverSyncInternal()
00848 {
00849
00850
00851
00852 if( kmkernel->mailCheckAborted() ) {
00853 resetSyncState();
00854 emit folderComplete( this, false );
00855 return;
00856 }
00857
00858
00859 switch( mSyncState ) {
00860 case SYNC_STATE_INITIAL:
00861 {
00862 mProgress = 0;
00863 foldersForDeletionOnServer.clear();
00864 newState( mProgress, i18n("Synchronizing"));
00865
00866 open("cachedimap");
00867 if ( !noContent() )
00868 mAccount->addLastUnreadMsgCount( this, countUnread() );
00869
00870
00871 ImapAccountBase::ConnectionState cs = mAccount->makeConnection();
00872 if ( cs == ImapAccountBase::Error ) {
00873
00874
00875
00876 newState( mProgress, i18n( "Error connecting to server %1" ).arg( mAccount->host() ) );
00877 close("cachedimap");
00878 emit folderComplete(this, false);
00879 break;
00880 } else if ( cs == ImapAccountBase::Connecting ) {
00881 mAccount->setAnnotationCheckPassed( false );
00882
00883 newState( mProgress, i18n("Connecting to %1").arg( mAccount->host() ) );
00884
00885 connect( mAccount, SIGNAL( connectionResult(int, const QString&) ),
00886 this, SLOT( slotConnectionResult(int, const QString&) ) );
00887 break;
00888 } else {
00889
00890
00891 mSyncState = SYNC_STATE_GET_USERRIGHTS;
00892
00893 }
00894 }
00895
00896
00897 case SYNC_STATE_GET_USERRIGHTS:
00898
00899
00900 mSyncState = SYNC_STATE_RENAME_FOLDER;
00901
00902 if( !noContent() && mAccount->hasACLSupport() ) {
00903
00904 mOldUserRights = mUserRights;
00905 newState( mProgress, i18n("Checking permissions"));
00906 connect( mAccount, SIGNAL( receivedUserRights( KMFolder* ) ),
00907 this, SLOT( slotReceivedUserRights( KMFolder* ) ) );
00908 mAccount->getUserRights( folder(), imapPath() );
00909 break;
00910 }
00911
00912 case SYNC_STATE_RENAME_FOLDER:
00913 {
00914 mSyncState = SYNC_STATE_CHECK_UIDVALIDITY;
00915
00916 bool isResourceFolder = kmkernel->iCalIface().isStandardResourceFolder( folder() );
00917 QString newName = mAccount->renamedFolder( imapPath() );
00918 if ( !newName.isEmpty() && !folder()->isSystemFolder() && !isResourceFolder ) {
00919 newState( mProgress, i18n("Renaming folder") );
00920 CachedImapJob *job = new CachedImapJob( newName, CachedImapJob::tRenameFolder, this );
00921 connect( job, SIGNAL( result(KMail::FolderJob *) ), this, SLOT( slotIncreaseProgress() ) );
00922 connect( job, SIGNAL( finished() ), this, SLOT( serverSyncInternal() ) );
00923 job->start();
00924 break;
00925 }
00926 }
00927
00928 case SYNC_STATE_CHECK_UIDVALIDITY:
00929 mSyncState = SYNC_STATE_CREATE_SUBFOLDERS;
00930 if( !noContent() ) {
00931 checkUidValidity();
00932 break;
00933 }
00934
00935
00936 case SYNC_STATE_CREATE_SUBFOLDERS:
00937 mSyncState = SYNC_STATE_PUT_MESSAGES;
00938 createNewFolders();
00939 break;
00940
00941 case SYNC_STATE_PUT_MESSAGES:
00942 mSyncState = SYNC_STATE_UPLOAD_FLAGS;
00943 if( !noContent() ) {
00944 uploadNewMessages();
00945 break;
00946 }
00947
00948 case SYNC_STATE_UPLOAD_FLAGS:
00949 mSyncState = SYNC_STATE_LIST_NAMESPACES;
00950 if( !noContent() ) {
00951
00952 if( uidMapDirty )
00953 reloadUidMap();
00954
00955
00956 if ( mUserRights <= 0 || ( mUserRights & (KMail::ACLJobs::WriteFlags ) ) ) {
00957 if ( !mUIDsOfLocallyChangedStatuses.isEmpty() || mStatusChangedLocally ) {
00958 uploadFlags();
00959 break;
00960 } else {
00961
00962 }
00963 } else if ( mUserRights & KMail::ACLJobs::WriteSeenFlag ) {
00964 if ( !mUIDsOfLocallyChangedStatuses.isEmpty() || mStatusChangedLocally ) {
00965 uploadSeenFlags();
00966 break;
00967 }
00968 }
00969 }
00970
00971
00972 case SYNC_STATE_LIST_NAMESPACES:
00973 if ( this == mAccount->rootFolder() ) {
00974 listNamespaces();
00975 break;
00976 }
00977 mSyncState = SYNC_STATE_LIST_SUBFOLDERS;
00978
00979
00980 case SYNC_STATE_LIST_SUBFOLDERS:
00981 newState( mProgress, i18n("Retrieving folderlist"));
00982 mSyncState = SYNC_STATE_LIST_SUBFOLDERS2;
00983 if( !listDirectory() ) {
00984 mSyncState = SYNC_STATE_INITIAL;
00985 KMessageBox::error(0, i18n("Error while retrieving the folderlist"));
00986 }
00987 break;
00988
00989 case SYNC_STATE_LIST_SUBFOLDERS2:
00990 mSyncState = SYNC_STATE_DELETE_SUBFOLDERS;
00991 mProgress += 10;
00992 newState( mProgress, i18n("Retrieving subfolders"));
00993 listDirectory2();
00994 break;
00995
00996 case SYNC_STATE_DELETE_SUBFOLDERS:
00997 mSyncState = SYNC_STATE_LIST_MESSAGES;
00998 if( !foldersForDeletionOnServer.isEmpty() ) {
00999 newState( mProgress, i18n("Deleting folders from server"));
01000 CachedImapJob* job = new CachedImapJob( foldersForDeletionOnServer,
01001 CachedImapJob::tDeleteFolders, this );
01002 connect( job, SIGNAL( result(KMail::FolderJob *) ), this, SLOT( slotIncreaseProgress() ) );
01003 connect( job, SIGNAL( finished() ), this, SLOT( slotFolderDeletionOnServerFinished() ) );
01004 job->start();
01005 break;
01006 }
01007
01008
01009
01010
01011 case SYNC_STATE_LIST_MESSAGES:
01012 mSyncState = SYNC_STATE_DELETE_MESSAGES;
01013 if( !noContent() ) {
01014 newState( mProgress, i18n("Retrieving message list"));
01015 listMessages();
01016 break;
01017 }
01018
01019
01020 case SYNC_STATE_DELETE_MESSAGES:
01021 mSyncState = SYNC_STATE_EXPUNGE_MESSAGES;
01022 if( !noContent() ) {
01023 if( deleteMessages() ) {
01024
01025 } else {
01026
01027 newState( mProgress, i18n("No messages to delete..."));
01028 mSyncState = SYNC_STATE_GET_MESSAGES;
01029 serverSyncInternal();
01030 }
01031 break;
01032 }
01033
01034
01035 case SYNC_STATE_EXPUNGE_MESSAGES:
01036 mSyncState = SYNC_STATE_GET_MESSAGES;
01037 if( !noContent() ) {
01038 newState( mProgress, i18n("Expunging deleted messages"));
01039 CachedImapJob *job = new CachedImapJob( QString::null,
01040 CachedImapJob::tExpungeFolder, this );
01041 connect( job, SIGNAL( result(KMail::FolderJob *) ), this, SLOT( slotIncreaseProgress() ) );
01042 connect( job, SIGNAL( finished() ), this, SLOT( serverSyncInternal() ) );
01043 job->start();
01044 break;
01045 }
01046
01047
01048 case SYNC_STATE_GET_MESSAGES:
01049 mSyncState = SYNC_STATE_HANDLE_INBOX;
01050 if( !noContent() ) {
01051 if( !mMsgsForDownload.isEmpty() ) {
01052 newState( mProgress, i18n("Retrieving new messages"));
01053 CachedImapJob *job = new CachedImapJob( mMsgsForDownload,
01054 CachedImapJob::tGetMessage,
01055 this );
01056 connect( job, SIGNAL( progress(unsigned long, unsigned long) ),
01057 this, SLOT( slotProgress(unsigned long, unsigned long) ) );
01058 connect( job, SIGNAL( finished() ), this, SLOT( slotUpdateLastUid() ) );
01059 connect( job, SIGNAL( finished() ), this, SLOT( serverSyncInternal() ) );
01060 job->start();
01061 mMsgsForDownload.clear();
01062 break;
01063 } else {
01064 newState( mProgress, i18n("No new messages from server"));
01065
01066
01067
01068
01069
01070 slotUpdateLastUid();
01071 if( mLastUid == 0 && uidWriteTimer == -1 ) {
01072
01073 if ( writeUidCache() == -1 ) {
01074 resetSyncState();
01075 emit folderComplete( this, false );
01076 return;
01077 }
01078 }
01079 }
01080 }
01081
01082
01083
01084 case SYNC_STATE_HANDLE_INBOX:
01085
01086 mProgress = 95;
01087 mSyncState = SYNC_STATE_TEST_ANNOTATIONS;
01088
01089 #define KOLAB_FOLDERTEST "/vendor/kolab/folder-test"
01090 case SYNC_STATE_TEST_ANNOTATIONS:
01091 mSyncState = SYNC_STATE_GET_ANNOTATIONS;
01092
01093 if( !mAccount->annotationCheckPassed() &&
01094 ( mUserRights <= 0 || ( mUserRights & ACLJobs::Administer ) )
01095 && !imapPath().isEmpty() && imapPath() != "/" ) {
01096 kdDebug(5006) << "Setting test attribute on folder: "<< folder()->prettyURL() << endl;
01097 newState( mProgress, i18n("Checking annotation support"));
01098
01099 KURL url = mAccount->getUrl();
01100 url.setPath( imapPath() );
01101 KMail::AnnotationList annotations;
01102
01103 KMail::AnnotationAttribute attr( KOLAB_FOLDERTEST, "value.shared", "true" );
01104 annotations.append( attr );
01105
01106 kdDebug(5006) << "Setting test attribute to "<< url << endl;
01107 KIO::Job* job = AnnotationJobs::multiSetAnnotation( mAccount->slave(),
01108 url, annotations );
01109 ImapAccountBase::jobData jd( url.url(), folder() );
01110 jd.cancellable = true;
01111 mAccount->insertJob(job, jd);
01112 connect(job, SIGNAL(result(KIO::Job *)),
01113 SLOT(slotTestAnnotationResult(KIO::Job *)));
01114 break;
01115 }
01116
01117 case SYNC_STATE_GET_ANNOTATIONS: {
01118 #define KOLAB_FOLDERTYPE "/vendor/kolab/folder-type"
01119 #define KOLAB_INCIDENCESFOR "/vendor/kolab/incidences-for"
01120 #define KOLAB_SHAREDSEEN "/vendor/cmu/cyrus-imapd/sharedseen"
01121
01122 mSyncState = SYNC_STATE_SET_ANNOTATIONS;
01123
01124 bool needToGetInitialAnnotations = false;
01125 if ( !noContent() ) {
01126
01127 if ( mAnnotationFolderType == "FROMSERVER" ) {
01128 needToGetInitialAnnotations = true;
01129 mAnnotationFolderType = QString::null;
01130 } else {
01131 updateAnnotationFolderType();
01132 }
01133 }
01134
01135
01136
01137 if ( !noContent() && mAccount->hasAnnotationSupport() &&
01138 ( kmkernel->iCalIface().isEnabled() || needToGetInitialAnnotations ) ) {
01139 QStringList annotations;
01140 if ( !mAnnotationFolderTypeChanged || mAnnotationFolderType.isEmpty() )
01141 annotations << KOLAB_FOLDERTYPE;
01142 if ( !mIncidencesForChanged )
01143 annotations << KOLAB_INCIDENCESFOR;
01144 if ( !mSharedSeenFlagsChanged )
01145 annotations << KOLAB_SHAREDSEEN;
01146 if ( !annotations.isEmpty() ) {
01147 newState( mProgress, i18n("Retrieving annotations"));
01148 KURL url = mAccount->getUrl();
01149 url.setPath( imapPath() );
01150 AnnotationJobs::MultiGetAnnotationJob* job =
01151 AnnotationJobs::multiGetAnnotation( mAccount->slave(), url, annotations );
01152 ImapAccountBase::jobData jd( url.url(), folder() );
01153 jd.cancellable = true;
01154 mAccount->insertJob(job, jd);
01155
01156 connect( job, SIGNAL(annotationResult(const QString&, const QString&, bool)),
01157 SLOT(slotAnnotationResult(const QString&, const QString&, bool)) );
01158 connect( job, SIGNAL(result(KIO::Job *)),
01159 SLOT(slotGetAnnotationResult(KIO::Job *)) );
01160 break;
01161 }
01162 }
01163 }
01164 case SYNC_STATE_SET_ANNOTATIONS:
01165
01166 mSyncState = SYNC_STATE_SET_ACLS;
01167 if ( !noContent() && mAccount->hasAnnotationSupport() &&
01168 ( mUserRights <= 0 || ( mUserRights & ACLJobs::Administer ) ) ) {
01169 newState( mProgress, i18n("Setting annotations"));
01170 KURL url = mAccount->getUrl();
01171 url.setPath( imapPath() );
01172 KMail::AnnotationList annotations;
01173 if ( mAnnotationFolderTypeChanged && !mAnnotationFolderType.isEmpty() ) {
01174 KMail::AnnotationAttribute attr( KOLAB_FOLDERTYPE, "value.shared", mAnnotationFolderType );
01175 annotations.append( attr );
01176 kdDebug(5006) << "Setting folder-type annotation for " << label() << " to " << mAnnotationFolderType << endl;
01177 }
01178 if ( mIncidencesForChanged ) {
01179 const QString val = incidencesForToString( mIncidencesFor );
01180 KMail::AnnotationAttribute attr( KOLAB_INCIDENCESFOR, "value.shared", val );
01181 annotations.append( attr );
01182 kdDebug(5006) << "Setting incidences-for annotation for " << label() << " to " << val << endl;
01183 }
01184 if ( mSharedSeenFlagsChanged ) {
01185 const QString val = mSharedSeenFlags ? "true" : "false";
01186 KMail::AnnotationAttribute attr( KOLAB_SHAREDSEEN, "value.shared", val );
01187 annotations.append( attr );
01188 kdDebug(5006) << k_funcinfo << "Setting sharedseen annotation for " << label() << " to " << val << endl;
01189 }
01190 if ( !annotations.isEmpty() ) {
01191 KIO::Job* job =
01192 AnnotationJobs::multiSetAnnotation( mAccount->slave(), url, annotations );
01193 ImapAccountBase::jobData jd( url.url(), folder() );
01194 jd.cancellable = true;
01195 mAccount->insertJob(job, jd);
01196
01197 connect(job, SIGNAL(annotationChanged( const QString&, const QString&, const QString& ) ),
01198 SLOT( slotAnnotationChanged( const QString&, const QString&, const QString& ) ));
01199 connect(job, SIGNAL(result(KIO::Job *)),
01200 SLOT(slotSetAnnotationResult(KIO::Job *)));
01201 break;
01202 }
01203 }
01204
01205 case SYNC_STATE_SET_ACLS:
01206 mSyncState = SYNC_STATE_GET_ACLS;
01207
01208 if( !noContent() && mAccount->hasACLSupport() &&
01209 ( mUserRights <= 0 || ( mUserRights & ACLJobs::Administer ) ) ) {
01210 bool hasChangedACLs = false;
01211 ACLList::ConstIterator it = mACLList.begin();
01212 for ( ; it != mACLList.end() && !hasChangedACLs; ++it ) {
01213 hasChangedACLs = (*it).changed;
01214 }
01215 if ( hasChangedACLs ) {
01216 newState( mProgress, i18n("Setting permissions"));
01217 KURL url = mAccount->getUrl();
01218 url.setPath( imapPath() );
01219 KIO::Job* job = KMail::ACLJobs::multiSetACL( mAccount->slave(), url, mACLList );
01220 ImapAccountBase::jobData jd( url.url(), folder() );
01221 mAccount->insertJob(job, jd);
01222
01223 connect(job, SIGNAL(result(KIO::Job *)),
01224 SLOT(slotMultiSetACLResult(KIO::Job *)));
01225 connect(job, SIGNAL(aclChanged( const QString&, int )),
01226 SLOT(slotACLChanged( const QString&, int )) );
01227 break;
01228 }
01229 }
01230
01231 case SYNC_STATE_GET_ACLS:
01232 mSyncState = SYNC_STATE_GET_QUOTA;
01233
01234 if( !noContent() && mAccount->hasACLSupport() ) {
01235 newState( mProgress, i18n( "Retrieving permissions" ) );
01236 mAccount->getACL( folder(), mImapPath );
01237 connect( mAccount, SIGNAL(receivedACL( KMFolder*, KIO::Job*, const KMail::ACLList& )),
01238 this, SLOT(slotReceivedACL( KMFolder*, KIO::Job*, const KMail::ACLList& )) );
01239 break;
01240 }
01241 case SYNC_STATE_GET_QUOTA:
01242
01243 mSyncState = SYNC_STATE_FIND_SUBFOLDERS;
01244 if( !noContent() && mAccount->hasQuotaSupport() ) {
01245 newState( mProgress, i18n("Getting quota information"));
01246 KURL url = mAccount->getUrl();
01247 url.setPath( imapPath() );
01248 KIO::Job* job = KMail::QuotaJobs::getStorageQuota( mAccount->slave(), url );
01249 ImapAccountBase::jobData jd( url.url(), folder() );
01250 mAccount->insertJob(job, jd);
01251 connect( job, SIGNAL( storageQuotaResult( const QuotaInfo& ) ),
01252 SLOT( slotStorageQuotaResult( const QuotaInfo& ) ) );
01253 connect( job, SIGNAL(result(KIO::Job *)),
01254 SLOT(slotQuotaResult(KIO::Job *)) );
01255 break;
01256 }
01257 case SYNC_STATE_FIND_SUBFOLDERS:
01258 {
01259 mProgress = 98;
01260 newState( mProgress, i18n("Updating cache file"));
01261
01262 mSyncState = SYNC_STATE_SYNC_SUBFOLDERS;
01263 mSubfoldersForSync.clear();
01264 mCurrentSubfolder = 0;
01265 if( folder() && folder()->child() ) {
01266 KMFolderNode *node = folder()->child()->first();
01267 while( node ) {
01268 if( !node->isDir() ) {
01269 KMFolderCachedImap* storage = static_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage());
01270
01271 if ( !storage->imapPath().isEmpty()
01272
01273 && !foldersForDeletionOnServer.contains( storage->imapPath() ) ) {
01274 mSubfoldersForSync << storage;
01275 } else {
01276 kdDebug(5006) << "Do not add " << storage->label()
01277 << " to synclist" << endl;
01278 }
01279 }
01280 node = folder()->child()->next();
01281 }
01282 }
01283
01284
01285 mProgress = 100;
01286 newState( mProgress, i18n("Synchronization done"));
01287 KURL url = mAccount->getUrl();
01288 url.setPath( imapPath() );
01289 kmkernel->iCalIface().folderSynced( folder(), url );
01290 }
01291
01292 if ( !mRecurse )
01293 mSubfoldersForSync.clear();
01294
01295
01296 case SYNC_STATE_SYNC_SUBFOLDERS:
01297 {
01298 if( mCurrentSubfolder ) {
01299 disconnect( mCurrentSubfolder, SIGNAL( folderComplete(KMFolderCachedImap*, bool) ),
01300 this, SLOT( slotSubFolderComplete(KMFolderCachedImap*, bool) ) );
01301 mCurrentSubfolder = 0;
01302 }
01303
01304 if( mSubfoldersForSync.isEmpty() ) {
01305 mSyncState = SYNC_STATE_INITIAL;
01306 mAccount->addUnreadMsgCount( this, countUnread() );
01307 close("cachedimap");
01308 emit folderComplete( this, true );
01309 } else {
01310 mCurrentSubfolder = mSubfoldersForSync.front();
01311 mSubfoldersForSync.pop_front();
01312 connect( mCurrentSubfolder, SIGNAL( folderComplete(KMFolderCachedImap*, bool) ),
01313 this, SLOT( slotSubFolderComplete(KMFolderCachedImap*, bool) ) );
01314
01315
01316 assert( !mCurrentSubfolder->imapPath().isEmpty() );
01317 mCurrentSubfolder->setAccount( account() );
01318 bool recurse = mCurrentSubfolder->noChildren() ? false : true;
01319 mCurrentSubfolder->serverSync( recurse );
01320 }
01321 }
01322 break;
01323
01324 default:
01325 kdDebug(5006) << "KMFolderCachedImap::serverSyncInternal() WARNING: no such state "
01326 << mSyncState << endl;
01327 }
01328 }
01329
01330
01331
01332
01333 void KMFolderCachedImap::slotConnectionResult( int errorCode, const QString& errorMsg )
01334 {
01335 disconnect( mAccount, SIGNAL( connectionResult(int, const QString&) ),
01336 this, SLOT( slotConnectionResult(int, const QString&) ) );
01337 if ( !errorCode ) {
01338
01339 mSyncState = SYNC_STATE_GET_USERRIGHTS;
01340 mProgress += 5;
01341 serverSyncInternal();
01342 } else {
01343
01344 newState( mProgress, KIO::buildErrorString( errorCode, errorMsg ));
01345 emit folderComplete(this, false);
01346 }
01347 }
01348
01349
01350 QValueList<unsigned long> KMFolderCachedImap::findNewMessages()
01351 {
01352 QValueList<unsigned long> result;
01353 for( int i = 0; i < count(); ++i ) {
01354 KMMsgBase *msg = getMsgBase( i );
01355 if( !msg ) continue;
01356 if ( msg->UID() == 0 )
01357 result.append( msg->getMsgSerNum() );
01358 }
01359 return result;
01360 }
01361
01362
01363 void KMFolderCachedImap::uploadNewMessages()
01364 {
01365 QValueList<unsigned long> newMsgs = findNewMessages();
01366 if( !newMsgs.isEmpty() ) {
01367 if ( mUserRights <= 0 || ( mUserRights & ( KMail::ACLJobs::Insert ) ) ) {
01368 newState( mProgress, i18n("Uploading messages to server"));
01369 CachedImapJob *job = new CachedImapJob( newMsgs, CachedImapJob::tPutMessage, this );
01370 connect( job, SIGNAL( progress( unsigned long, unsigned long) ),
01371 this, SLOT( slotPutProgress(unsigned long, unsigned long) ) );
01372 connect( job, SIGNAL( finished() ), this, SLOT( serverSyncInternal() ) );
01373 job->start();
01374 return;
01375 } else {
01376 KMCommand *command = rescueUnsyncedMessages();
01377 connect( command, SIGNAL( completed( KMCommand * ) ),
01378 this, SLOT( serverSyncInternal() ) );
01379 }
01380 } else {
01381 if ( mUserRights != mOldUserRights && (mOldUserRights & KMail::ACLJobs::Insert)
01382 && !(mUserRights & KMail::ACLJobs::Insert) ) {
01383
01384 KMessageBox::information( 0, i18n("<p>Your access rights to folder <b>%1</b> have been restricted, "
01385 "it will no longer be possible to add messages to this folder.</p>").arg( folder()->prettyURL() ),
01386 i18n("Acces rights revoked"), "KMailACLRevocationNotification" );
01387 }
01388 }
01389 newState( mProgress, i18n("No messages to upload to server"));
01390 serverSyncInternal();
01391 }
01392
01393
01394 void KMFolderCachedImap::slotPutProgress( unsigned long done, unsigned long total )
01395 {
01396
01397 int progressSpan = 10;
01398 newState( mProgress + (progressSpan * done) / total, QString::null );
01399 if ( done == total )
01400 mProgress += progressSpan;
01401 }
01402
01403
01404 void KMFolderCachedImap::uploadFlags()
01405 {
01406 if ( !uidMap.isEmpty() ) {
01407 mStatusFlagsJobs = 0;
01408 newState( mProgress, i18n("Uploading status of messages to server"));
01409
01410
01411 QMap< QString, QStringList > groups;
01412
01413 for( int i = 0; i < count(); ++i ) {
01414 KMMsgBase* msg = getMsgBase( i );
01415 if( !msg || msg->UID() == 0 )
01416
01417 continue;
01418 if ( mUIDsOfLocallyChangedStatuses.findIndex( msg->UID() ) < 0 && !mStatusChangedLocally ) {
01419
01420 continue;
01421 }
01422
01423 QString flags = KMFolderImap::statusToFlags(msg->status(), mPermanentFlags);
01424
01425 QString uid;
01426 uid.setNum( msg->UID() );
01427 groups[flags].append(uid);
01428 }
01429 QMapIterator< QString, QStringList > dit;
01430 for( dit = groups.begin(); dit != groups.end(); ++dit ) {
01431 QCString flags = dit.key().latin1();
01432 QStringList sets = KMFolderImap::makeSets( (*dit), true );
01433 mStatusFlagsJobs += sets.count();
01434
01435 for( QStringList::Iterator slit = sets.begin(); slit != sets.end(); ++slit ) {
01436 QString imappath = imapPath() + ";UID=" + ( *slit );
01437 mAccount->setImapStatus(folder(), imappath, flags);
01438 }
01439 }
01440
01441
01442 if ( mStatusFlagsJobs ) {
01443 connect( mAccount, SIGNAL( imapStatusChanged(KMFolder*, const QString&, bool) ),
01444 this, SLOT( slotImapStatusChanged(KMFolder*, const QString&, bool) ) );
01445 return;
01446 }
01447 }
01448 newState( mProgress, i18n("No messages to upload to server"));
01449 serverSyncInternal();
01450 }
01451
01452 void KMFolderCachedImap::uploadSeenFlags()
01453 {
01454 if ( !uidMap.isEmpty() ) {
01455 mStatusFlagsJobs = 0;
01456 newState( mProgress, i18n("Uploading status of messages to server"));
01457
01458 QValueList<ulong> seenUids, unseenUids;
01459 for( int i = 0; i < count(); ++i ) {
01460 KMMsgBase* msg = getMsgBase( i );
01461 if( !msg || msg->UID() == 0 )
01462
01463 continue;
01464
01465 if ( mUIDsOfLocallyChangedStatuses.findIndex( msg->UID() ) < 0 && !mStatusChangedLocally ) {
01466
01467 continue;
01468 }
01469
01470 if ( msg->status() & KMMsgStatusOld || msg->status() & KMMsgStatusRead )
01471 seenUids.append( msg->UID() );
01472 else
01473 unseenUids.append( msg->UID() );
01474 }
01475 if ( !seenUids.isEmpty() ) {
01476 QStringList sets = KMFolderImap::makeSets( seenUids, true );
01477 mStatusFlagsJobs += sets.count();
01478 for( QStringList::Iterator it = sets.begin(); it != sets.end(); ++it ) {
01479 QString imappath = imapPath() + ";UID=" + ( *it );
01480 mAccount->setImapSeenStatus( folder(), imappath, true );
01481 }
01482 }
01483 if ( !unseenUids.isEmpty() ) {
01484 QStringList sets = KMFolderImap::makeSets( unseenUids, true );
01485 mStatusFlagsJobs += sets.count();
01486 for( QStringList::Iterator it = sets.begin(); it != sets.end(); ++it ) {
01487 QString imappath = imapPath() + ";UID=" + ( *it );
01488 mAccount->setImapSeenStatus( folder(), imappath, false );
01489 }
01490 }
01491
01492 if ( mStatusFlagsJobs ) {
01493 connect( mAccount, SIGNAL( imapStatusChanged(KMFolder*, const QString&, bool) ),
01494 this, SLOT( slotImapStatusChanged(KMFolder*, const QString&, bool) ) );
01495 return;
01496 }
01497 }
01498 newState( mProgress, i18n("No messages to upload to server"));
01499 serverSyncInternal();
01500 }
01501
01502 void KMFolderCachedImap::slotImapStatusChanged(KMFolder* folder, const QString&, bool cont)
01503 {
01504 if ( mSyncState == SYNC_STATE_INITIAL ){
01505
01506 return;
01507 }
01508
01509 if ( folder->storage() == this ) {
01510 --mStatusFlagsJobs;
01511 if ( mStatusFlagsJobs == 0 || !cont )
01512 disconnect( mAccount, SIGNAL( imapStatusChanged(KMFolder*, const QString&, bool) ),
01513 this, SLOT( slotImapStatusChanged(KMFolder*, const QString&, bool) ) );
01514 if ( mStatusFlagsJobs == 0 && cont ) {
01515 mProgress += 5;
01516 serverSyncInternal();
01517
01518 }
01519 }
01520 }
01521
01522
01523 void KMFolderCachedImap::setStatus( int idx, KMMsgStatus status, bool toggle)
01524 {
01525 KMFolderMaildir::setStatus( idx, status, toggle );
01526 const KMMsgBase *msg = getMsgBase( idx );
01527 Q_ASSERT( msg );
01528 if ( msg )
01529 mUIDsOfLocallyChangedStatuses.append( msg->UID() );
01530 }
01531
01532 void KMFolderCachedImap::setStatus(QValueList<int>& ids, KMMsgStatus status, bool toggle)
01533 {
01534 KMFolderMaildir::setStatus(ids, status, toggle);
01535 for (QValueList<int>::iterator it = ids.begin(); it != ids.end(); it++ ) {
01536 const KMMsgBase *msg = getMsgBase( *it );
01537 Q_ASSERT( msg );
01538 if ( msg )
01539 mUIDsOfLocallyChangedStatuses.append( msg->UID() );
01540 }
01541 }
01542
01543
01544 void KMFolderCachedImap::createNewFolders()
01545 {
01546 QValueList<KMFolderCachedImap*> newFolders = findNewFolders();
01547
01548 if( !newFolders.isEmpty() ) {
01549 newState( mProgress, i18n("Creating subfolders on server"));
01550 CachedImapJob *job = new CachedImapJob( newFolders, CachedImapJob::tAddSubfolders, this );
01551 connect( job, SIGNAL( result(KMail::FolderJob *) ), this, SLOT( slotIncreaseProgress() ) );
01552 connect( job, SIGNAL( finished() ), this, SLOT( serverSyncInternal() ) );
01553 job->start();
01554 } else {
01555 serverSyncInternal();
01556 }
01557 }
01558
01559 QValueList<KMFolderCachedImap*> KMFolderCachedImap::findNewFolders()
01560 {
01561 QValueList<KMFolderCachedImap*> newFolders;
01562 if( folder() && folder()->child() ) {
01563 KMFolderNode *node = folder()->child()->first();
01564 while( node ) {
01565 if( !node->isDir() ) {
01566 if( static_cast<KMFolder*>(node)->folderType() != KMFolderTypeCachedImap ) {
01567 kdError(5006) << "KMFolderCachedImap::findNewFolders(): ARGH!!! "
01568 << node->name() << " is not an IMAP folder\n";
01569 node = folder()->child()->next();
01570 assert(0);
01571 }
01572 KMFolderCachedImap* folder = static_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage());
01573 if( folder->imapPath().isEmpty() ) {
01574 newFolders << folder;
01575 }
01576 }
01577 node = folder()->child()->next();
01578 }
01579 }
01580 return newFolders;
01581 }
01582
01583 bool KMFolderCachedImap::deleteMessages()
01584 {
01585
01586 QPtrList<KMMessage> msgsForDeletion;
01587
01588
01589
01590
01591
01592 QStringList uids;
01593 QMap<ulong,int>::const_iterator it = uidMap.constBegin();
01594 for( ; it != uidMap.end(); it++ ) {
01595 ulong uid ( it.key() );
01596 if( uid!=0 && !uidsOnServer.find( uid ) ) {
01597 uids << QString::number( uid );
01598 msgsForDeletion.append( getMsg( *it ) );
01599 }
01600 }
01601
01602 if( !msgsForDeletion.isEmpty() ) {
01603 #if MAIL_LOSS_DEBUGGING
01604 if ( KMessageBox::warningYesNo(
01605 0, i18n( "<qt><p>Mails on the server in folder <b>%1</b> were deleted. "
01606 "Do you want to delete them locally?<br>UIDs: %2</p></qt>" )
01607 .arg( folder()->prettyURL() ).arg( uids.join(",") ) ) == KMessageBox::Yes )
01608 #endif
01609 removeMsg( msgsForDeletion );
01610 }
01611
01612 if ( mUserRights > 0 && !( mUserRights & KMail::ACLJobs::Delete ) )
01613 return false;
01614
01615
01616 if( !uidsForDeletionOnServer.isEmpty() ) {
01617 newState( mProgress, i18n("Deleting removed messages from server"));
01618 QStringList sets = KMFolderImap::makeSets( uidsForDeletionOnServer, true );
01619 uidsForDeletionOnServer.clear();
01620 kdDebug(5006) << "Deleting " << sets.count() << " sets of messages from server folder " << imapPath() << endl;
01621 CachedImapJob *job = new CachedImapJob( sets, CachedImapJob::tDeleteMessage, this );
01622 connect( job, SIGNAL( result(KMail::FolderJob *) ),
01623 this, SLOT( slotDeleteMessagesResult(KMail::FolderJob *) ) );
01624 job->start();
01625 return true;
01626 } else {
01627 return false;
01628 }
01629 }
01630
01631 void KMFolderCachedImap::slotDeleteMessagesResult( KMail::FolderJob* job )
01632 {
01633 if ( job->error() ) {
01634
01635 mSyncState = SYNC_STATE_GET_MESSAGES;
01636 } else {
01637
01638 mDeletedUIDsSinceLastSync.clear();
01639 }
01640 mProgress += 10;
01641 serverSyncInternal();
01642 }
01643
01644 void KMFolderCachedImap::checkUidValidity() {
01645
01646
01647 if( imapPath().isEmpty() || imapPath() == "/" )
01648
01649 serverSyncInternal();
01650 else {
01651 newState( mProgress, i18n("Checking folder validity"));
01652 CachedImapJob *job = new CachedImapJob( FolderJob::tCheckUidValidity, this );
01653 connect( job, SIGNAL(permanentFlags(int)), SLOT(slotPermanentFlags(int)) );
01654 connect( job, SIGNAL( result( KMail::FolderJob* ) ),
01655 this, SLOT( slotCheckUidValidityResult( KMail::FolderJob* ) ) );
01656 job->start();
01657 }
01658 }
01659
01660 void KMFolderCachedImap::slotCheckUidValidityResult( KMail::FolderJob* job )
01661 {
01662 if ( job->error() ) {
01663
01664
01665 mSyncState = SYNC_STATE_HANDLE_INBOX;
01666 }
01667 mProgress += 5;
01668 serverSyncInternal();
01669 }
01670
01671 void KMFolderCachedImap::slotPermanentFlags(int flags)
01672 {
01673 mPermanentFlags = flags;
01674 }
01675
01676
01677
01678 void KMFolderCachedImap::listMessages() {
01679 bool groupwareOnly = GlobalSettings::self()->showOnlyGroupwareFoldersForGroupwareAccount()
01680 && GlobalSettings::self()->theIMAPResourceAccount() == (int)mAccount->id()
01681 && folder()->isSystemFolder()
01682 && mImapPath == "/INBOX/";
01683
01684
01685 if( imapPath() == "/" || groupwareOnly ) {
01686 serverSyncInternal();
01687 return;
01688 }
01689
01690 if( !mAccount->slave() ) {
01691 resetSyncState();
01692 emit folderComplete( this, false );
01693 return;
01694 }
01695 uidsOnServer.clear();
01696 uidsOnServer.resize( count() * 2 );
01697 uidsForDeletionOnServer.clear();
01698 mMsgsForDownload.clear();
01699 mUidsForDownload.clear();
01700
01701 mFoundAnIMAPDigest = false;
01702
01703 CachedImapJob* job = new CachedImapJob( FolderJob::tListMessages, this );
01704 connect( job, SIGNAL( result(KMail::FolderJob *) ),
01705 this, SLOT( slotGetLastMessagesResult(KMail::FolderJob *) ) );
01706 job->start();
01707 }
01708
01709 void KMFolderCachedImap::slotGetLastMessagesResult(KMail::FolderJob *job)
01710 {
01711 getMessagesResult(job, true);
01712 }
01713
01714
01715 void KMFolderCachedImap::slotGetMessagesData(KIO::Job * job, const QByteArray & data)
01716 {
01717 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
01718 if ( it == mAccount->jobsEnd() ) {
01719 kdDebug(5006) << "could not find job!?!?!" << endl;
01720
01721
01722
01723 mSyncState = SYNC_STATE_HANDLE_INBOX;
01724 serverSyncInternal();
01725 return;
01726 }
01727 (*it).cdata += QCString(data, data.size() + 1);
01728 int pos = (*it).cdata.find("\r\n--IMAPDIGEST");
01729 if (pos > 0) {
01730 int a = (*it).cdata.find("\r\nX-uidValidity:");
01731 if (a != -1) {
01732 int b = (*it).cdata.find("\r\n", a + 17);
01733 setUidValidity((*it).cdata.mid(a + 17, b - a - 17));
01734 }
01735 a = (*it).cdata.find("\r\nX-Access:");
01736
01737
01738
01739
01740
01741 if (a != -1 && mUserRights == -1 ) {
01742 int b = (*it).cdata.find("\r\n", a + 12);
01743 const QString access = (*it).cdata.mid(a + 12, b - a - 12);
01744 setReadOnly( access == "Read only" );
01745 }
01746 (*it).cdata.remove(0, pos);
01747 mFoundAnIMAPDigest = true;
01748 }
01749 pos = (*it).cdata.find("\r\n--IMAPDIGEST", 1);
01750
01751 if ( uidsOnServer.size() == 0 )
01752 uidsOnServer.resize( KMail::nextPrime( 2000 ) );
01753 const int v = 42;
01754 while (pos >= 0) {
01755
01756
01757
01758
01759
01760
01761
01762
01763
01764 const QCString& entry( (*it).cdata );
01765 const int indexOfUID = entry.find("X-UID", 16);
01766 const int startOfUIDValue = indexOfUID + 7;
01767 const int indexOfLength = entry.find("X-Length", startOfUIDValue );
01768 const int startOfLengthValue = indexOfLength + 10;
01769 const int indexOfFlags = entry.find("X-Flags", startOfLengthValue );
01770 const int startOfFlagsValue = indexOfFlags + 9;
01771
01772 const int flags = entry.mid( startOfFlagsValue, entry.find( '\r', startOfFlagsValue ) - startOfFlagsValue ).toInt();
01773 const ulong size = entry.mid( startOfLengthValue, entry.find( '\r', startOfLengthValue ) - startOfLengthValue ).toULong();
01774 const ulong uid = entry.mid( startOfUIDValue, entry.find( '\r', startOfUIDValue ) - startOfUIDValue ).toULong();
01775
01776 const bool deleted = ( flags & 8 );
01777 if ( !deleted ) {
01778 if( uid != 0 ) {
01779 if ( uidsOnServer.count() == uidsOnServer.size() ) {
01780 uidsOnServer.resize( KMail::nextPrime( uidsOnServer.size() * 2 ) );
01781
01782 }
01783 uidsOnServer.insert( uid, &v );
01784 }
01785 bool redownload = false;
01786 if ( uid <= lastUid() ) {
01787
01788
01789
01790
01791
01792
01793
01794
01795
01796
01797 KMMsgBase *existingMessage = findByUID(uid);
01798 if( !existingMessage ) {
01799 #if MAIL_LOSS_DEBUGGING
01800 kdDebug(5006) << "Looking at uid " << uid << " high water is: " << lastUid() << " we should delete it" << endl;
01801 #endif
01802
01803 if ( mDeletedUIDsSinceLastSync.contains(uid) ) {
01804 if ( mUserRights <= 0 || ( mUserRights & KMail::ACLJobs::Delete ) ) {
01805 #if MAIL_LOSS_DEBUGGING
01806 kdDebug(5006) << "message with uid " << uid << " is gone from local cache. Must be deleted on server!!!" << endl;
01807 #endif
01808 uidsForDeletionOnServer << uid;
01809 } else {
01810 redownload = true;
01811 }
01812 } else {
01813 kdDebug(5006) << "WARNING: ####### " << endl;
01814 kdDebug(5006) << "Message locally missing but not deleted in folder: " << folder()->prettyURL() << endl;
01815 kdDebug(5006) << "The missing UID: " << uid << ". It will be redownloaded " << endl;
01816 redownload = true;
01817 }
01818
01819 } else {
01820
01821
01822
01823 if ( !mReadOnly || !GlobalSettings::allowLocalFlags() ) {
01824
01825 KMFolderImap::flagsToStatus( existingMessage, flags, false, mReadOnly ? INT_MAX : mPermanentFlags );
01826 } else if ( mUserRights & KMail::ACLJobs::WriteSeenFlag ) {
01827 KMFolderImap::seenFlagToStatus( existingMessage, flags );
01828 }
01829 }
01830
01831 }
01832 if ( uid > lastUid() || redownload ) {
01833 #if MAIL_LOSS_DEBUGGING
01834 kdDebug(5006) << "Looking at uid " << uid << " high water is: " << lastUid() << " we should download it" << endl;
01835 #endif
01836
01837
01838 if ( !uidMap.contains( uid ) ) {
01839 mMsgsForDownload << KMail::CachedImapJob::MsgForDownload(uid, flags, size);
01840 if( imapPath() == "/INBOX/" )
01841 mUidsForDownload << uid;
01842 }
01843
01844 if ( uid > mTentativeHighestUid ) {
01845 #if MAIL_LOSS_DEBUGGING
01846 kdDebug(5006) << "Setting the tentative highest UID to: " << uid << endl;
01847 #endif
01848 mTentativeHighestUid = uid;
01849 }
01850 }
01851 }
01852 (*it).cdata.remove(0, pos);
01853 (*it).done++;
01854 pos = (*it).cdata.find("\r\n--IMAPDIGEST", 1);
01855 }
01856 }
01857
01858 void KMFolderCachedImap::getMessagesResult( KMail::FolderJob *job, bool lastSet )
01859 {
01860 mProgress += 10;
01861 if ( !job->error() && !mFoundAnIMAPDigest ) {
01862 kdWarning(5006) << "######## Folderlisting did not complete, but there was no error! "
01863 "Aborting sync of folder: " << folder()->prettyURL() << endl;
01864 #if MAIL_LOSS_DEBUGGING
01865 kmkernel->emergencyExit( i18n("Folder listing failed in interesting ways." ) );
01866 #endif
01867 }
01868 if( job->error() ) {
01869 mContentState = imapNoInformation;
01870 mSyncState = SYNC_STATE_HANDLE_INBOX;
01871 } else {
01872 if( lastSet ) {
01873 mContentState = imapFinished;
01874 mUIDsOfLocallyChangedStatuses.clear();
01875 mStatusChangedLocally = false;
01876 }
01877 }
01878 serverSyncInternal();
01879 }
01880
01881 void KMFolderCachedImap::slotProgress(unsigned long done, unsigned long total)
01882 {
01883 int progressSpan = 100 - 5 - mProgress;
01884
01885
01886
01887 newState( mProgress + (progressSpan * done) / total, QString::null );
01888 }
01889
01890 void KMFolderCachedImap::setAccount(KMAcctCachedImap *aAccount)
01891 {
01892 assert( aAccount->isA("KMAcctCachedImap") );
01893 mAccount = aAccount;
01894 if( imapPath()=="/" ) aAccount->setFolder( folder() );
01895
01896
01897 QString newName = mAccount->renamedFolder( imapPath() );
01898 if ( !newName.isEmpty() )
01899 folder()->setLabel( newName );
01900
01901 if( !folder() || !folder()->child() || !folder()->child()->count() ) return;
01902 for( KMFolderNode* node = folder()->child()->first(); node;
01903 node = folder()->child()->next() )
01904 if (!node->isDir())
01905 static_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage())->setAccount(aAccount);
01906 }
01907
01908 void KMFolderCachedImap::listNamespaces()
01909 {
01910 ImapAccountBase::ListType type = ImapAccountBase::List;
01911 if ( mAccount->onlySubscribedFolders() )
01912 type = ImapAccountBase::ListSubscribed;
01913
01914 kdDebug(5006) << "listNamespaces " << mNamespacesToList << endl;
01915 if ( mNamespacesToList.isEmpty() ) {
01916 mSyncState = SYNC_STATE_DELETE_SUBFOLDERS;
01917 mPersonalNamespacesCheckDone = true;
01918
01919 QStringList ns = mAccount->namespaces()[ImapAccountBase::OtherUsersNS];
01920 ns += mAccount->namespaces()[ImapAccountBase::SharedNS];
01921 mNamespacesToCheck = ns.count();
01922 for ( QStringList::Iterator it = ns.begin(); it != ns.end(); ++it )
01923 {
01924 if ( (*it).isEmpty() ) {
01925
01926 --mNamespacesToCheck;
01927 continue;
01928 }
01929 KMail::ListJob* job = new KMail::ListJob( mAccount, type, this, mAccount->addPathToNamespace( *it ) );
01930 job->setHonorLocalSubscription( true );
01931 connect( job, SIGNAL(receivedFolders(const QStringList&, const QStringList&,
01932 const QStringList&, const QStringList&, const ImapAccountBase::jobData&)),
01933 this, SLOT(slotCheckNamespace(const QStringList&, const QStringList&,
01934 const QStringList&, const QStringList&, const ImapAccountBase::jobData&)));
01935 job->start();
01936 }
01937 if ( mNamespacesToCheck == 0 ) {
01938 serverSyncInternal();
01939 }
01940 return;
01941 }
01942 mPersonalNamespacesCheckDone = false;
01943
01944 QString ns = mNamespacesToList.front();
01945 mNamespacesToList.pop_front();
01946
01947 mSyncState = SYNC_STATE_LIST_SUBFOLDERS2;
01948 newState( mProgress, i18n("Retrieving folders for namespace %1").arg(ns));
01949 KMail::ListJob* job = new KMail::ListJob( mAccount, type, this,
01950 mAccount->addPathToNamespace( ns ) );
01951 job->setNamespace( ns );
01952 job->setHonorLocalSubscription( true );
01953 connect( job, SIGNAL(receivedFolders(const QStringList&, const QStringList&,
01954 const QStringList&, const QStringList&, const ImapAccountBase::jobData&)),
01955 this, SLOT(slotListResult(const QStringList&, const QStringList&,
01956 const QStringList&, const QStringList&, const ImapAccountBase::jobData&)));
01957 job->start();
01958 }
01959
01960 void KMFolderCachedImap::slotCheckNamespace( const QStringList& subfolderNames,
01961 const QStringList& subfolderPaths,
01962 const QStringList& subfolderMimeTypes,
01963 const QStringList& subfolderAttributes,
01964 const ImapAccountBase::jobData& jobData )
01965 {
01966 Q_UNUSED( subfolderPaths );
01967 Q_UNUSED( subfolderMimeTypes );
01968 Q_UNUSED( subfolderAttributes );
01969 --mNamespacesToCheck;
01970 kdDebug(5006) << "slotCheckNamespace " << subfolderNames << ",remain=" <<
01971 mNamespacesToCheck << endl;
01972
01973
01974
01975 QString name = jobData.path.mid( 1, jobData.path.length()-2 );
01976 name.remove( mAccount->delimiterForNamespace( name ) );
01977 if ( name.isEmpty() ) {
01978
01979 kdWarning(5006) << "slotCheckNamespace: ignoring empty folder!" << endl;
01980 return;
01981 }
01982
01983 folder()->createChildFolder();
01984 KMFolderNode *node = 0;
01985 for ( node = folder()->child()->first(); node;
01986 node = folder()->child()->next())
01987 {
01988 if ( !node->isDir() && node->name() == name )
01989 break;
01990 }
01991 if ( !subfolderNames.isEmpty() ) {
01992 if ( node ) {
01993
01994 kdDebug(5006) << "found namespace folder " << name << endl;
01995 } else
01996 {
01997
01998 kdDebug(5006) << "create namespace folder " << name << endl;
01999 KMFolder* newFolder = folder()->child()->createFolder( name, false,
02000 KMFolderTypeCachedImap );
02001 if ( newFolder ) {
02002 KMFolderCachedImap *f = static_cast<KMFolderCachedImap*>( newFolder->storage() );
02003 f->setImapPath( mAccount->addPathToNamespace( name ) );
02004 f->setNoContent( true );
02005 f->setAccount( mAccount );
02006 f->close("cachedimap");
02007 kmkernel->dimapFolderMgr()->contentsChanged();
02008 }
02009 }
02010 } else {
02011 if ( node ) {
02012 kdDebug(5006) << "delete namespace folder " << name << endl;
02013 KMFolder* fld = static_cast<KMFolder*>(node);
02014 kmkernel->dimapFolderMgr()->remove( fld );
02015 }
02016 }
02017
02018 if ( mNamespacesToCheck == 0 ) {
02019
02020 serverSyncInternal();
02021 }
02022 }
02023
02024
02025
02026 bool KMFolderCachedImap::listDirectory()
02027 {
02028 if( !mAccount->slave() ) {
02029 resetSyncState();
02030 emit folderComplete( this, false );
02031 return false;
02032 }
02033 mSubfolderState = imapInProgress;
02034
02035
02036 ImapAccountBase::ListType type = ImapAccountBase::List;
02037 if ( mAccount->onlySubscribedFolders() )
02038 type = ImapAccountBase::ListSubscribed;
02039 KMail::ListJob* job = new KMail::ListJob( mAccount, type, this );
02040 job->setHonorLocalSubscription( true );
02041 connect( job, SIGNAL(receivedFolders(const QStringList&, const QStringList&,
02042 const QStringList&, const QStringList&, const ImapAccountBase::jobData&)),
02043 this, SLOT(slotListResult(const QStringList&, const QStringList&,
02044 const QStringList&, const QStringList&, const ImapAccountBase::jobData&)));
02045 job->start();
02046
02047 return true;
02048 }
02049
02050 void KMFolderCachedImap::slotListResult( const QStringList& folderNames,
02051 const QStringList& folderPaths,
02052 const QStringList& folderMimeTypes,
02053 const QStringList& folderAttributes,
02054 const ImapAccountBase::jobData& jobData )
02055 {
02056 Q_UNUSED( jobData );
02057
02058
02059 mSubfolderNames = folderNames;
02060 mSubfolderPaths = folderPaths;
02061 mSubfolderMimeTypes = folderMimeTypes;
02062 mSubfolderState = imapFinished;
02063 mSubfolderAttributes = folderAttributes;
02064 kdDebug(5006) << "##### setting subfolder attributes: " << mSubfolderAttributes << endl;
02065
02066 folder()->createChildFolder();
02067 KMFolderNode *node = folder()->child()->first();
02068 bool root = ( this == mAccount->rootFolder() );
02069
02070 QPtrList<KMFolder> toRemove;
02071 bool emptyList = ( root && mSubfolderNames.empty() );
02072 if ( !emptyList ) {
02073 while (node) {
02074 if (!node->isDir() ) {
02075 KMFolderCachedImap *f = static_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage());
02076
02077 if ( mSubfolderNames.findIndex(node->name()) == -1 ) {
02078 QString name = node->name();
02079
02080
02081 bool isInNamespace = ( jobData.curNamespace.isEmpty() ||
02082 jobData.curNamespace == mAccount->namespaceForFolder( f ) );
02083
02084 bool ignore = root && ( f->imapPath() == "/INBOX/" ||
02085 mAccount->isNamespaceFolder( name ) || !isInNamespace );
02086
02087
02088 if( !f->imapPath().isEmpty() && !ignore ) {
02089
02090
02091 toRemove.append( f->folder() );
02092 kdDebug(5006) << node->name() << " isn't on the server. It has an imapPath -> delete it locally" << endl;
02093 }
02094 } else {
02095
02096
02100 int index = mSubfolderNames.findIndex( node->name() );
02101 f->mFolderAttributes = folderAttributes[ index ];
02102 }
02103 } else {
02104
02105 }
02106 node = folder()->child()->next();
02107 }
02108 }
02109
02110 for ( KMFolder* doomed=toRemove.first(); doomed; doomed = toRemove.next() ) {
02111 rescueUnsyncedMessagesAndDeleteFolder( doomed );
02112 }
02113
02114 mProgress += 5;
02115
02116
02117 slotRescueDone( 0 );
02118 }
02119
02120
02121 void KMFolderCachedImap::listDirectory2()
02122 {
02123 QString path = folder()->path();
02124 kmkernel->dimapFolderMgr()->quiet(true);
02125
02126 bool root = ( this == mAccount->rootFolder() );
02127 if ( root && !mAccount->hasInbox() )
02128 {
02129 KMFolderCachedImap *f = 0;
02130 KMFolderNode *node;
02131
02132 for (node = folder()->child()->first(); node; node = folder()->child()->next())
02133 if (!node->isDir() && node->name() == "INBOX") break;
02134 if (node) {
02135 f = static_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage());
02136 } else {
02137 KMFolder* newFolder = folder()->child()->createFolder("INBOX", true, KMFolderTypeCachedImap);
02138 if ( newFolder ) {
02139 f = static_cast<KMFolderCachedImap*>(newFolder->storage());
02140 }
02141 }
02142 if ( f ) {
02143 f->setAccount( mAccount );
02144 f->setImapPath( "/INBOX/" );
02145 f->folder()->setLabel( i18n("inbox") );
02146 }
02147 if (!node) {
02148 if ( f )
02149 f->close("cachedimap");
02150 kmkernel->dimapFolderMgr()->contentsChanged();
02151 }
02152
02153 mAccount->setHasInbox( true );
02154 }
02155
02156 if ( root && !mSubfolderNames.isEmpty() ) {
02157 KMFolderCachedImap* parent =
02158 findParent( mSubfolderPaths.first(), mSubfolderNames.first() );
02159 if ( parent ) {
02160 kdDebug(5006) << "KMFolderCachedImap::listDirectory2 - pass listing to "
02161 << parent->label() << endl;
02162 mSubfolderNames.clear();
02163 }
02164 }
02165
02166
02167 QValueVector<int> foldersNewOnServer;
02168 for (uint i = 0; i < mSubfolderNames.count(); i++) {
02169
02170
02171 KMFolderCachedImap *f = 0;
02172 KMFolderNode *node = 0;
02173 for (node = folder()->child()->first(); node;
02174 node = folder()->child()->next())
02175 if (!node->isDir() && node->name() == mSubfolderNames[i]) break;
02176
02177 if (!node) {
02178
02179
02180 QString subfolderPath = mSubfolderPaths[i];
02181
02182
02183
02184 bool locallyDeleted = mAccount->isDeletedFolder( subfolderPath );
02185
02186
02187
02188 if ( !locallyDeleted && mAccount->isPreviouslyDeletedFolder( subfolderPath ) ) {
02189 locallyDeleted = KMessageBox::warningYesNo(
02190 0, i18n( "<qt><p>It seems that the folder <b>%1</b> was deleted. Do you want to delete it from the server?</p></qt>" ).arg( mSubfolderNames[i] ), QString::null, KStdGuiItem::del(), KStdGuiItem::cancel() ) == KMessageBox::Yes;
02191 }
02192
02193 if ( locallyDeleted ) {
02194 kdDebug(5006) << subfolderPath << " was deleted locally => delete on server." << endl;
02195 foldersForDeletionOnServer += mAccount->deletedFolderPaths( subfolderPath );
02196 } else {
02197 kdDebug(5006) << subfolderPath << " is a new folder on the server => create local cache" << endl;
02198 foldersNewOnServer.append( i );
02199 }
02200 } else {
02201 if( static_cast<KMFolder*>(node)->folderType() == KMFolderTypeCachedImap )
02202 f = dynamic_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage());
02203 if( f ) {
02204
02205
02206
02207 f->setAccount(mAccount);
02208 f->setNoContent(mSubfolderMimeTypes[i] == "inode/directory");
02209 f->setNoChildren(mSubfolderMimeTypes[i] == "message/digest");
02210 f->setImapPath(mSubfolderPaths[i]);
02211 }
02212 }
02213 }
02214
02215
02216
02217
02218
02219
02220
02221
02222
02223
02224
02225 if ( GlobalSettings::self()->showOnlyGroupwareFoldersForGroupwareAccount()
02226 && GlobalSettings::self()->theIMAPResourceAccount() == (int)mAccount->id()
02227 && mAccount->hasAnnotationSupport()
02228 && GlobalSettings::self()->theIMAPResourceEnabled()
02229 && !foldersNewOnServer.isEmpty() ) {
02230
02231 QStringList paths;
02232 for ( uint i = 0; i < foldersNewOnServer.count(); ++i )
02233 paths << mSubfolderPaths[ foldersNewOnServer[i] ];
02234
02235 AnnotationJobs::MultiUrlGetAnnotationJob* job =
02236 AnnotationJobs::multiUrlGetAnnotation( mAccount->slave(), mAccount->getUrl(), paths, KOLAB_FOLDERTYPE );
02237 ImapAccountBase::jobData jd( QString::null, folder() );
02238 jd.cancellable = true;
02239 mAccount->insertJob(job, jd);
02240 connect( job, SIGNAL(result(KIO::Job *)),
02241 SLOT(slotMultiUrlGetAnnotationResult(KIO::Job *)) );
02242
02243 } else {
02244 createFoldersNewOnServerAndFinishListing( foldersNewOnServer );
02245 }
02246 }
02247
02248 void KMFolderCachedImap::createFoldersNewOnServerAndFinishListing( const QValueVector<int> foldersNewOnServer )
02249 {
02250 for ( uint i = 0; i < foldersNewOnServer.count(); ++i ) {
02251 int idx = foldersNewOnServer[i];
02252 KMFolder* newFolder = folder()->child()->createFolder( mSubfolderNames[idx], false, KMFolderTypeCachedImap);
02253 if (newFolder) {
02254 KMFolderCachedImap *f = dynamic_cast<KMFolderCachedImap*>(newFolder->storage());
02255 kdDebug(5006) << " ####### Locally creating folder " << mSubfolderNames[idx] <<endl;
02256 f->close("cachedimap");
02257 f->setAccount(mAccount);
02258 f->mAnnotationFolderType = "FROMSERVER";
02259 f->setNoContent(mSubfolderMimeTypes[idx] == "inode/directory");
02260 f->setNoChildren(mSubfolderMimeTypes[idx] == "message/digest");
02261 f->setImapPath(mSubfolderPaths[idx]);
02262 f->mFolderAttributes = mSubfolderAttributes[idx];
02263 kdDebug(5006) << " ####### Attributes: " << f->mFolderAttributes <<endl;
02264
02265 kmkernel->dimapFolderMgr()->contentsChanged();
02266 } else {
02267 kdDebug(5006) << "can't create folder " << mSubfolderNames[idx] <<endl;
02268 }
02269 }
02270
02271 kmkernel->dimapFolderMgr()->quiet(false);
02272 emit listComplete(this);
02273 if ( !mPersonalNamespacesCheckDone ) {
02274
02275 mSyncState = SYNC_STATE_LIST_NAMESPACES;
02276 }
02277 serverSyncInternal();
02278 }
02279
02280
02281 KMFolderCachedImap* KMFolderCachedImap::findParent( const QString& path,
02282 const QString& name )
02283 {
02284 QString parent = path.left( path.length() - name.length() - 2 );
02285 if ( parent.length() > 1 )
02286 {
02287
02288 parent = parent.right( parent.length() - 1 );
02289 if ( parent != label() )
02290 {
02291 KMFolderNode *node = folder()->child()->first();
02292
02293 while ( node )
02294 {
02295 if ( node->name() == parent )
02296 {
02297 KMFolder* fld = static_cast<KMFolder*>(node);
02298 KMFolderCachedImap* imapFld =
02299 static_cast<KMFolderCachedImap*>( fld->storage() );
02300 return imapFld;
02301 }
02302 node = folder()->child()->next();
02303 }
02304 }
02305 }
02306 return 0;
02307 }
02308
02309 void KMFolderCachedImap::slotSubFolderComplete(KMFolderCachedImap* sub, bool success)
02310 {
02311 Q_UNUSED(sub);
02312
02313 if ( success ) {
02314 serverSyncInternal();
02315 }
02316 else
02317 {
02318
02319 if ( mCurrentSubfolder ) {
02320 Q_ASSERT( sub == mCurrentSubfolder );
02321 disconnect( mCurrentSubfolder, SIGNAL( folderComplete(KMFolderCachedImap*, bool) ),
02322 this, SLOT( slotSubFolderComplete(KMFolderCachedImap*, bool) ) );
02323 mCurrentSubfolder = 0;
02324 }
02325
02326 mSubfoldersForSync.clear();
02327 mSyncState = SYNC_STATE_INITIAL;
02328 close("cachedimap");
02329 emit folderComplete( this, false );
02330 }
02331 }
02332
02333 void KMFolderCachedImap::slotSimpleData(KIO::Job * job, const QByteArray & data)
02334 {
02335 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
02336 if (it == mAccount->jobsEnd()) return;
02337 QBuffer buff((*it).data);
02338 buff.open(IO_WriteOnly | IO_Append);
02339 buff.writeBlock(data.data(), data.size());
02340 buff.close();
02341 }
02342
02343 FolderJob*
02344 KMFolderCachedImap::doCreateJob( KMMessage *msg, FolderJob::JobType jt, KMFolder *folder,
02345 QString, const AttachmentStrategy* ) const
02346 {
02347 QPtrList<KMMessage> msgList;
02348 msgList.append( msg );
02349 CachedImapJob *job = new CachedImapJob( msgList, jt, folder? static_cast<KMFolderCachedImap*>( folder->storage() ):0 );
02350 job->setParentFolder( this );
02351 return job;
02352 }
02353
02354 FolderJob*
02355 KMFolderCachedImap::doCreateJob( QPtrList<KMMessage>& msgList, const QString& sets,
02356 FolderJob::JobType jt, KMFolder *folder ) const
02357 {
02358
02359 Q_UNUSED( sets );
02360 CachedImapJob *job = new CachedImapJob( msgList, jt, folder? static_cast<KMFolderCachedImap*>( folder->storage() ):0 );
02361 job->setParentFolder( this );
02362 return job;
02363 }
02364
02365 void
02366 KMFolderCachedImap::setUserRights( unsigned int userRights )
02367 {
02368 mUserRights = userRights;
02369 writeConfigKeysWhichShouldNotGetOverwrittenByReadConfig();
02370 }
02371
02372 void
02373 KMFolderCachedImap::slotReceivedUserRights( KMFolder* folder )
02374 {
02375 if ( folder->storage() == this ) {
02376 disconnect( mAccount, SIGNAL( receivedUserRights( KMFolder* ) ),
02377 this, SLOT( slotReceivedUserRights( KMFolder* ) ) );
02378 if ( mUserRights == 0 )
02379 mUserRights = -1;
02380 else
02381 setReadOnly( ( mUserRights & KMail::ACLJobs::Insert ) == 0 );
02382 mProgress += 5;
02383 serverSyncInternal();
02384 }
02385 }
02386
02387 void
02388 KMFolderCachedImap::setReadOnly( bool readOnly )
02389 {
02390 if ( readOnly != mReadOnly ) {
02391 mReadOnly = readOnly;
02392 emit readOnlyChanged( folder() );
02393 }
02394 }
02395
02396 void
02397 KMFolderCachedImap::slotReceivedACL( KMFolder* folder, KIO::Job*, const KMail::ACLList& aclList )
02398 {
02399 if ( folder->storage() == this ) {
02400 disconnect( mAccount, SIGNAL(receivedACL( KMFolder*, KIO::Job*, const KMail::ACLList& )),
02401 this, SLOT(slotReceivedACL( KMFolder*, KIO::Job*, const KMail::ACLList& )) );
02402 mACLList = aclList;
02403 serverSyncInternal();
02404 }
02405 }
02406
02407 void
02408 KMFolderCachedImap::slotStorageQuotaResult( const QuotaInfo& info )
02409 {
02410 setQuotaInfo( info );
02411 }
02412
02413 void KMFolderCachedImap::setQuotaInfo( const QuotaInfo & info )
02414 {
02415 if ( info != mQuotaInfo ) {
02416 mQuotaInfo = info;
02417 writeConfigKeysWhichShouldNotGetOverwrittenByReadConfig();
02418 emit folderSizeChanged();
02419 }
02420 }
02421
02422 void
02423 KMFolderCachedImap::setACLList( const ACLList& arr )
02424 {
02425 mACLList = arr;
02426 }
02427
02428 void
02429 KMFolderCachedImap::slotMultiSetACLResult(KIO::Job *job)
02430 {
02431 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
02432 if ( it == mAccount->jobsEnd() ) return;
02433 if ( (*it).parent != folder() ) return;
02434
02435 if ( job->error() )
02436
02437
02438 job->showErrorDialog();
02439 else
02440 kmkernel->iCalIface().addFolderChange( folder(), KMailICalIfaceImpl::ACL );
02441
02442 if (mAccount->slave()) mAccount->removeJob(job);
02443 serverSyncInternal();
02444 }
02445
02446 void
02447 KMFolderCachedImap::slotACLChanged( const QString& userId, int permissions )
02448 {
02449
02450
02451 for( ACLList::Iterator it = mACLList.begin(); it != mACLList.end(); ++it ) {
02452 if ( (*it).userId == userId && (*it).permissions == permissions ) {
02453 if ( permissions == -1 )
02454 mACLList.erase( it );
02455 else
02456 (*it).changed = false;
02457 return;
02458 }
02459 }
02460 }
02461
02462
02463 void KMFolderCachedImap::resetSyncState()
02464 {
02465 if ( mSyncState == SYNC_STATE_INITIAL ) return;
02466 mSubfoldersForSync.clear();
02467 mSyncState = SYNC_STATE_INITIAL;
02468 close("cachedimap");
02469
02470 KPIM::ProgressItem *progressItem = mAccount->mailCheckProgressItem();
02471 QString str = i18n("Aborted");
02472 if (progressItem)
02473 progressItem->setStatus( str );
02474 emit statusMsg( str );
02475 }
02476
02477 void KMFolderCachedImap::slotIncreaseProgress()
02478 {
02479 mProgress += 5;
02480 }
02481
02482 void KMFolderCachedImap::newState( int progress, const QString& syncStatus )
02483 {
02484
02485 KPIM::ProgressItem *progressItem = mAccount->mailCheckProgressItem();
02486 if( progressItem )
02487 progressItem->setCompletedItems( progress );
02488 if ( !syncStatus.isEmpty() ) {
02489 QString str;
02490
02491 if ( mAccount->imapFolder() == this )
02492 str = syncStatus;
02493 else
02494 str = QString( "%1: %2" ).arg( label() ).arg( syncStatus );
02495 if( progressItem )
02496 progressItem->setStatus( str );
02497 emit statusMsg( str );
02498 }
02499 if( progressItem )
02500 progressItem->updateProgress();
02501 }
02502
02503 void KMFolderCachedImap::setSubfolderState( imapState state )
02504 {
02505 mSubfolderState = state;
02506 if ( state == imapNoInformation && folder()->child() )
02507 {
02508
02509 KMFolderNode* node;
02510 QPtrListIterator<KMFolderNode> it( *folder()->child() );
02511 for ( ; (node = it.current()); )
02512 {
02513 ++it;
02514 if (node->isDir()) continue;
02515 KMFolder *folder = static_cast<KMFolder*>(node);
02516 static_cast<KMFolderCachedImap*>(folder->storage())->setSubfolderState( state );
02517 }
02518 }
02519 }
02520
02521 void KMFolderCachedImap::setImapPath(const QString &path)
02522 {
02523 mImapPath = path;
02524 }
02525
02526
02527
02528
02529
02530
02531 void KMFolderCachedImap::updateAnnotationFolderType()
02532 {
02533 QString oldType = mAnnotationFolderType;
02534 QString oldSubType;
02535 int dot = oldType.find( '.' );
02536 if ( dot != -1 ) {
02537 oldType.truncate( dot );
02538 oldSubType = mAnnotationFolderType.mid( dot + 1 );
02539 }
02540
02541 QString newType, newSubType;
02542
02543 if ( kmkernel->iCalIface().storageFormat( folder() ) == KMailICalIfaceImpl::StorageXML ) {
02544 newType = KMailICalIfaceImpl::annotationForContentsType( mContentsType );
02545 if ( kmkernel->iCalIface().isStandardResourceFolder( folder() ) )
02546 newSubType = "default";
02547 else if ( oldSubType != "default" )
02548 newSubType = oldSubType;
02549 }
02550
02551
02552 if ( newType != oldType || newSubType != oldSubType ) {
02553 mAnnotationFolderType = newType + ( newSubType.isEmpty() ? QString::null : "."+newSubType );
02554 mAnnotationFolderTypeChanged = true;
02555 kdDebug(5006) << mImapPath << ": updateAnnotationFolderType: '" << mAnnotationFolderType << "', was (" << oldType << " " << oldSubType << ") => mAnnotationFolderTypeChanged set to TRUE" << endl;
02556 }
02557
02558 writeConfigKeysWhichShouldNotGetOverwrittenByReadConfig();
02559 }
02560
02561 void KMFolderCachedImap::setIncidencesFor( IncidencesFor incfor )
02562 {
02563 if ( mIncidencesFor != incfor ) {
02564 mIncidencesFor = incfor;
02565 mIncidencesForChanged = true;
02566 }
02567 }
02568
02569 void KMFolderCachedImap::setSharedSeenFlags(bool b)
02570 {
02571 if ( mSharedSeenFlags != b ) {
02572 mSharedSeenFlags = b;
02573 mSharedSeenFlagsChanged = true;
02574 }
02575 }
02576
02577 void KMFolderCachedImap::slotAnnotationResult(const QString& entry, const QString& value, bool found)
02578 {
02579 if ( entry == KOLAB_FOLDERTYPE ) {
02580
02581
02582
02583
02584
02585 if ( found ) {
02586 QString type = value;
02587 QString subtype;
02588 int dot = value.find( '.' );
02589 if ( dot != -1 ) {
02590 type.truncate( dot );
02591 subtype = value.mid( dot + 1 );
02592 }
02593 bool foundKnownType = false;
02594 for ( uint i = 0 ; i <= ContentsTypeLast; ++i ) {
02595 FolderContentsType contentsType = static_cast<KMail::FolderContentsType>( i );
02596 if ( type == KMailICalIfaceImpl::annotationForContentsType( contentsType ) ) {
02597
02598
02599 if ( contentsType != ContentsTypeMail )
02600 kmkernel->iCalIface().setStorageFormat( folder(), KMailICalIfaceImpl::StorageXML );
02601 mAnnotationFolderType = value;
02602 if ( folder()->parent()->owner()->idString() != GlobalSettings::self()->theIMAPResourceFolderParent()
02603 && GlobalSettings::self()->theIMAPResourceEnabled()
02604 && subtype == "default" ) {
02605
02606
02607 mAnnotationFolderType = type;
02608 kdDebug(5006) << mImapPath << ": slotGetAnnotationResult: parent folder is " << folder()->parent()->owner()->idString() << " => truncating annotation to " << value << endl;
02609 }
02610 setContentsType( contentsType );
02611 mAnnotationFolderTypeChanged = false;
02612 foundKnownType = true;
02613
02614
02615
02616
02617
02618 if ( contentsType != ContentsTypeMail )
02619 markUnreadAsRead();
02620
02621
02622 writeConfigKeysWhichShouldNotGetOverwrittenByReadConfig();
02623 break;
02624 }
02625 }
02626 if ( !foundKnownType && !mReadOnly ) {
02627
02628
02629 mAnnotationFolderTypeChanged = true;
02630 }
02631
02632 }
02633 else if ( !mReadOnly ) {
02634
02635
02636 mAnnotationFolderTypeChanged = true;
02637 }
02638 } else if ( entry == KOLAB_INCIDENCESFOR ) {
02639 if ( found ) {
02640 mIncidencesFor = incidencesForFromString( value );
02641 Q_ASSERT( mIncidencesForChanged == false );
02642 }
02643 } else if ( entry == KOLAB_SHAREDSEEN ) {
02644 if ( found ) {
02645 mSharedSeenFlags = value == "true";
02646 }
02647 }
02648 }
02649
02650 void KMFolderCachedImap::slotGetAnnotationResult( KIO::Job* job )
02651 {
02652 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
02653 Q_ASSERT( it != mAccount->jobsEnd() );
02654 if ( it == mAccount->jobsEnd() ) return;
02655 Q_ASSERT( (*it).parent == folder() );
02656 if ( (*it).parent != folder() ) return;
02657
02658 AnnotationJobs::GetAnnotationJob* annjob = static_cast<AnnotationJobs::GetAnnotationJob *>( job );
02659 if ( annjob->error() ) {
02660 if ( job->error() == KIO::ERR_UNSUPPORTED_ACTION ) {
02661
02662 if ( GlobalSettings::self()->theIMAPResourceStorageFormat() == GlobalSettings::EnumTheIMAPResourceStorageFormat::XML
02663 && (uint)GlobalSettings::self()->theIMAPResourceAccount() == mAccount->id() )
02664 KMessageBox::error( 0, i18n( "The IMAP server %1 does not have support for IMAP annotations. The XML storage cannot be used on this server; please re-configure KMail differently." ).arg( mAccount->host() ) );
02665 mAccount->setHasNoAnnotationSupport();
02666 }
02667 else
02668 kdWarning(5006) << "slotGetAnnotationResult: " << job->errorString() << endl;
02669 }
02670
02671 if (mAccount->slave()) mAccount->removeJob(job);
02672 mProgress += 2;
02673 serverSyncInternal();
02674 }
02675
02676 void KMFolderCachedImap::slotMultiUrlGetAnnotationResult( KIO::Job* job )
02677 {
02678 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
02679 Q_ASSERT( it != mAccount->jobsEnd() );
02680 if ( it == mAccount->jobsEnd() ) return;
02681 Q_ASSERT( (*it).parent == folder() );
02682 if ( (*it).parent != folder() ) return;
02683
02684 QValueVector<int> folders;
02685 AnnotationJobs::MultiUrlGetAnnotationJob* annjob
02686 = static_cast<AnnotationJobs::MultiUrlGetAnnotationJob *>( job );
02687 if ( annjob->error() ) {
02688 if ( job->error() == KIO::ERR_UNSUPPORTED_ACTION ) {
02689
02690 if ( GlobalSettings::self()->theIMAPResourceStorageFormat() == GlobalSettings::EnumTheIMAPResourceStorageFormat::XML
02691 && (uint)GlobalSettings::self()->theIMAPResourceAccount() == mAccount->id() )
02692 KMessageBox::error( 0, i18n( "The IMAP server %1 doesn't have support for imap annotations. The XML storage cannot be used on this server, please re-configure KMail differently" ).arg( mAccount->host() ) );
02693 mAccount->setHasNoAnnotationSupport();
02694 }
02695 else
02696 kdWarning(5006) << "slotGetMultiUrlAnnotationResult: " << job->errorString() << endl;
02697 } else {
02698
02699 QMap<QString, QString> annotations = annjob->annotations();
02700 QMap<QString, QString>::Iterator it = annotations.begin();
02701 for ( ; it != annotations.end(); ++it ) {
02702 const QString folderPath = it.key();
02703 const QString annotation = it.data();
02704 kdDebug(5006) << k_funcinfo << "Folder: " << folderPath << " has type: " << annotation << endl;
02705
02706 QString type(annotation);
02707 int dot = annotation.find( '.' );
02708 if ( dot != -1 ) type.truncate( dot );
02709 type = type.simplifyWhiteSpace();
02710
02711 const int idx = mSubfolderPaths.findIndex( folderPath );
02712 const bool isNoContent = mSubfolderMimeTypes[idx] == "inode/directory";
02713 if ( ( isNoContent && type.isEmpty() )
02714 || ( !type.isEmpty() && type != KMailICalIfaceImpl::annotationForContentsType( ContentsTypeMail ) ) ) {
02715 folders.append( idx );
02716 kdDebug(5006) << k_funcinfo << " subscribing to: " << folderPath << endl;
02717 } else {
02718 kdDebug(5006) << k_funcinfo << " automatically unsubscribing from: " << folderPath << endl;
02719 mAccount->changeLocalSubscription( folderPath, false );
02720 }
02721 }
02722 }
02723
02724 if (mAccount->slave()) mAccount->removeJob(job);
02725 createFoldersNewOnServerAndFinishListing( folders );
02726 }
02727
02728 void KMFolderCachedImap::slotQuotaResult( KIO::Job* job )
02729 {
02730 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
02731 Q_ASSERT( it != mAccount->jobsEnd() );
02732 if ( it == mAccount->jobsEnd() ) return;
02733 Q_ASSERT( (*it).parent == folder() );
02734 if ( (*it).parent != folder() ) return;
02735
02736 QuotaJobs::GetStorageQuotaJob* quotajob = static_cast<QuotaJobs::GetStorageQuotaJob *>( job );
02737 QuotaInfo empty;
02738 if ( quotajob->error() ) {
02739 if ( job->error() == KIO::ERR_UNSUPPORTED_ACTION ) {
02740
02741 mAccount->setHasNoQuotaSupport();
02742 setQuotaInfo( empty );
02743 }
02744 else
02745 kdWarning(5006) << "slotGetQuotaResult: " << job->errorString() << endl;
02746 }
02747
02748 if (mAccount->slave()) mAccount->removeJob(job);
02749 mProgress += 2;
02750 serverSyncInternal();
02751 }
02752
02753 void
02754 KMFolderCachedImap::slotAnnotationChanged( const QString& entry, const QString& attribute, const QString& value )
02755 {
02756 Q_UNUSED( attribute );
02757 Q_UNUSED( value );
02758
02759 if ( entry == KOLAB_FOLDERTYPE )
02760 mAnnotationFolderTypeChanged = false;
02761 else if ( entry == KOLAB_INCIDENCESFOR ) {
02762 mIncidencesForChanged = false;
02763
02764
02765 kmkernel->iCalIface().addFolderChange( folder(), KMailICalIfaceImpl::ACL );
02766 } else if ( entry == KOLAB_SHAREDSEEN ) {
02767 mSharedSeenFlagsChanged = false;
02768 }
02769 }
02770
02771 void KMFolderCachedImap::slotTestAnnotationResult(KIO::Job *job)
02772 {
02773 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
02774 Q_ASSERT( it != mAccount->jobsEnd() );
02775 if ( it == mAccount->jobsEnd() ) return;
02776 Q_ASSERT( (*it).parent == folder() );
02777 if ( (*it).parent != folder() ) return;
02778
02779 mAccount->setAnnotationCheckPassed( true );
02780 if ( job->error() ) {
02781 kdDebug(5006) << "Test Annotation was not passed, disabling annotation support" << endl;
02782 mAccount->setHasNoAnnotationSupport( );
02783 } else {
02784 kdDebug(5006) << "Test Annotation was passed OK" << endl;
02785 }
02786 if (mAccount->slave()) mAccount->removeJob(job);
02787 serverSyncInternal();
02788 }
02789
02790 void
02791 KMFolderCachedImap::slotSetAnnotationResult(KIO::Job *job)
02792 {
02793 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
02794 if ( it == mAccount->jobsEnd() ) return;
02795 if ( (*it).parent != folder() ) return;
02796
02797 bool cont = true;
02798 if ( job->error() ) {
02799
02800 if ( job->error() == KIO::ERR_UNSUPPORTED_ACTION && contentsType() == ContentsTypeMail ) {
02801 if (mAccount->slave()) mAccount->removeJob(job);
02802 } else {
02803 cont = mAccount->handleJobError( job, i18n( "Error while setting annotation: " ) + '\n' );
02804 }
02805 } else {
02806 if (mAccount->slave()) mAccount->removeJob(job);
02807 }
02808 if ( cont )
02809 serverSyncInternal();
02810 }
02811
02812 void KMFolderCachedImap::slotUpdateLastUid()
02813 {
02814 if( mTentativeHighestUid != 0 ) {
02815
02816
02817
02818
02819
02820
02821
02822
02823
02824
02825
02826 bool sane = count() == 0;
02827
02828 for (int i=0;i<count(); i++ ) {
02829 ulong uid = getMsgBase(i)->UID();
02830 if ( uid > mTentativeHighestUid && uid > lastUid() ) {
02831 kdWarning(5006) << "DANGER: Either the server listed a wrong highest uid, "
02832 "or we parsed it wrong. Send email to adam@kde.org, please, and include this log." << endl;
02833 kdWarning(5006) << "uid: " << uid << " mTentativeHighestUid: " << mTentativeHighestUid << endl;
02834 assert( false );
02835 break;
02836 } else {
02837 sane = true;
02838 }
02839 }
02840 if (sane) {
02841 #if MAIL_LOSS_DEBUGGING
02842 kdDebug(5006) << "Tentative highest UID test was sane, writing out: " << mTentativeHighestUid << endl;
02843 #endif
02844 setLastUid( mTentativeHighestUid );
02845 }
02846 }
02847 mTentativeHighestUid = 0;
02848 }
02849
02850 bool KMFolderCachedImap::isMoveable() const
02851 {
02852 return ( hasChildren() == HasNoChildren &&
02853 !folder()->isSystemFolder() ) ? true : false;
02854 }
02855
02856 void KMFolderCachedImap::slotFolderDeletionOnServerFinished()
02857 {
02858 for ( QStringList::const_iterator it = foldersForDeletionOnServer.constBegin();
02859 it != foldersForDeletionOnServer.constEnd(); ++it ) {
02860 KURL url( mAccount->getUrl() );
02861 url.setPath( *it );
02862 kmkernel->iCalIface().folderDeletedOnServer( url );
02863 }
02864 serverSyncInternal();
02865 }
02866
02867 int KMFolderCachedImap::createIndexFromContentsRecursive()
02868 {
02869 if ( !folder() || !folder()->child() )
02870 return 0;
02871
02872 KMFolderNode *node = 0;
02873 for( QPtrListIterator<KMFolderNode> it( *folder()->child() ); (node = it.current()); ++it ) {
02874 if( !node->isDir() ) {
02875 KMFolderCachedImap* storage = static_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage());
02876 kdDebug() << k_funcinfo << "Re-indexing: " << storage->folder()->label() << endl;
02877 int rv = storage->createIndexFromContentsRecursive();
02878 if ( rv > 0 )
02879 return rv;
02880 }
02881 }
02882
02883 return createIndexFromContents();
02884 }
02885
02886 void KMFolderCachedImap::setAlarmsBlocked( bool blocked )
02887 {
02888 mAlarmsBlocked = blocked;
02889 }
02890
02891 bool KMFolderCachedImap::alarmsBlocked() const
02892 {
02893 return mAlarmsBlocked;
02894 }
02895
02896 bool KMFolderCachedImap::isCloseToQuota() const
02897 {
02898 bool closeToQuota = false;
02899 if ( mQuotaInfo.isValid() && mQuotaInfo.max().toInt() > 0 ) {
02900 const int ratio = mQuotaInfo.current().toInt() * 100 / mQuotaInfo.max().toInt();
02901
02902 closeToQuota = ( ratio > 0 && ratio >= GlobalSettings::closeToQuotaThreshold() );
02903 }
02904
02905 return closeToQuota;
02906 }
02907
02908 KMCommand* KMFolderCachedImap::rescueUnsyncedMessages()
02909 {
02910 QValueList<unsigned long> newMsgs = findNewMessages();
02911 kdDebug() << k_funcinfo << newMsgs << " of " << count() << endl;
02912 if ( newMsgs.isEmpty() )
02913 return 0;
02914 KMFolder *dest = 0;
02915 bool manualMove = true;
02916 while ( GlobalSettings::autoLostFoundMove() ) {
02917
02918 KMFolder *inboxFolder = kmkernel->findFolderById( QString(".%1.directory/INBOX").arg( account()->id() ) );
02919 if ( !inboxFolder ) {
02920 kdWarning(5006) << k_funcinfo << "inbox not found!" << endl;
02921 break;
02922 }
02923 KMFolderDir *inboxDir = inboxFolder->child();
02924 if ( !inboxDir && !inboxFolder->storage() )
02925 break;
02926 assert( inboxFolder->storage()->folderType() == KMFolderTypeCachedImap );
02927
02928
02929 KMFolderNode *node;
02930 KMFolder *lfFolder = 0;
02931 if ( !(node = inboxDir->hasNamedFolder( i18n("lost+found") )) ) {
02932 kdDebug(5006) << k_funcinfo << "creating lost+found folder" << endl;
02933 KMFolder* folder = kmkernel->dimapFolderMgr()->createFolder(
02934 i18n("lost+found"), false, KMFolderTypeCachedImap, inboxDir );
02935 if ( !folder || !folder->storage() )
02936 break;
02937 static_cast<KMFolderCachedImap*>( folder->storage() )->initializeFrom(
02938 static_cast<KMFolderCachedImap*>( inboxFolder->storage() ) );
02939 folder->storage()->setContentsType( KMail::ContentsTypeMail );
02940 folder->storage()->writeConfig();
02941 lfFolder = folder;
02942 } else {
02943 kdDebug(5006) << k_funcinfo << "found lost+found folder" << endl;
02944 lfFolder = dynamic_cast<KMFolder*>( node );
02945 }
02946 if ( !lfFolder || !lfFolder->createChildFolder() || !lfFolder->storage() )
02947 break;
02948
02949
02950 QDate today = QDate::currentDate();
02951 QString baseName = folder()->label() + "-" + QString::number( today.year() )
02952 + (today.month() < 10 ? "0" : "" ) + QString::number( today.month() )
02953 + (today.day() < 10 ? "0" : "" ) + QString::number( today.day() );
02954 QString name = baseName;
02955 int suffix = 0;
02956 while ( (node = lfFolder->child()->hasNamedFolder( name )) ) {
02957 ++suffix;
02958 name = baseName + '-' + QString::number( suffix );
02959 }
02960 kdDebug(5006) << k_funcinfo << "creating lost+found folder " << name << endl;
02961 dest = kmkernel->dimapFolderMgr()->createFolder( name, false, KMFolderTypeCachedImap, lfFolder->child() );
02962 if ( !dest || !dest->storage() )
02963 break;
02964 static_cast<KMFolderCachedImap*>( dest->storage() )->initializeFrom(
02965 static_cast<KMFolderCachedImap*>( lfFolder->storage() ) );
02966 dest->storage()->setContentsType( contentsType() );
02967 dest->storage()->writeConfig();
02968
02969 KMessageBox::sorry( 0, i18n("<p>There are new messages in folder <b>%1</b>, which "
02970 "have not been uploaded to the server yet, but the folder has been deleted "
02971 "on the server or you do not "
02972 "have sufficient access rights on the folder to upload them.</p>"
02973 "<p>All affected messages will therefore be moved to <b>%2</b> "
02974 "to avoid data loss.</p>").arg( folder()->prettyURL() ).arg( dest->prettyURL() ),
02975 i18n("Insufficient access rights") );
02976 manualMove = false;
02977 break;
02978 }
02979
02980 if ( manualMove ) {
02981 const QString msg ( i18n( "<p>There are new messages in this folder (%1), which "
02982 "have not been uploaded to the server yet, but the folder has been deleted "
02983 "on the server or you do not "
02984 "have sufficient access rights on the folder now to upload them. "
02985 "Please contact your administrator to allow upload of new messages "
02986 "to you, or move them out of this folder.</p> "
02987 "<p>Do you want to move these messages to another folder now?</p>").arg( folder()->prettyURL() ) );
02988 if ( KMessageBox::warningYesNo( 0, msg, QString::null, i18n("Move"), i18n("Do Not Move") ) == KMessageBox::Yes ) {
02989 KMail::KMFolderSelDlg dlg( kmkernel->getKMMainWidget(),
02990 i18n("Move Messages to Folder"), true );
02991 if ( dlg.exec() ) {
02992 dest = dlg.folder();
02993 }
02994 }
02995 }
02996 if ( dest ) {
02997 QPtrList<KMMsgBase> msgs;
02998 for( int i = 0; i < count(); ++i ) {
02999 KMMsgBase *msg = getMsgBase( i );
03000 if( !msg ) continue;
03001 if ( msg->UID() == 0 )
03002 msgs.append( msg );
03003 }
03004 KMCommand *command = new KMMoveCommand( dest, msgs );
03005 command->start();
03006 return command;
03007 }
03008 return 0;
03009 }
03010
03011 void KMFolderCachedImap::rescueUnsyncedMessagesAndDeleteFolder( KMFolder *folder, bool root )
03012 {
03013 kdDebug() << k_funcinfo << folder << " " << root << endl;
03014 if ( root )
03015 mToBeDeletedAfterRescue.append( folder );
03016 folder->open("cachedimap");
03017 KMFolderCachedImap* storage = dynamic_cast<KMFolderCachedImap*>( folder->storage() );
03018 if ( storage ) {
03019 KMCommand *command = storage->rescueUnsyncedMessages();
03020 if ( command ) {
03021 connect( command, SIGNAL(completed(KMCommand*)),
03022 SLOT(slotRescueDone(KMCommand*)) );
03023 ++mRescueCommandCount;
03024 } else {
03025
03026
03027 folder->close("cachedimap");
03028 }
03029 }
03030 if ( folder->child() ) {
03031 KMFolderNode *node = folder->child()->first();
03032 while (node) {
03033 if (!node->isDir() ) {
03034 KMFolder *subFolder = static_cast<KMFolder*>( node );
03035 rescueUnsyncedMessagesAndDeleteFolder( subFolder, false );
03036 }
03037 node = folder->child()->next();
03038 }
03039 }
03040 }
03041
03042 void KMFolderCachedImap::slotRescueDone(KMCommand * command)
03043 {
03044
03045 if ( command )
03046 --mRescueCommandCount;
03047 if ( mRescueCommandCount > 0 )
03048 return;
03049 for ( QValueList<KMFolder*>::ConstIterator it = mToBeDeletedAfterRescue.constBegin();
03050 it != mToBeDeletedAfterRescue.constEnd(); ++it ) {
03051 kmkernel->dimapFolderMgr()->remove( *it );
03052 }
03053 mToBeDeletedAfterRescue.clear();
03054 serverSyncInternal();
03055 }
03056
03057 bool KMFolderCachedImap::canDeleteMessages() const
03058 {
03059 if ( isReadOnly() )
03060 return false;
03061 if ( userRights() > 0 && !(userRights() & ACLJobs::Delete) )
03062 return false;
03063 return true;
03064 }
03065
03066 #include "kmfoldercachedimap.moc"