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