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.insert( ( *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( std::set<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.empty() || mStatusChangedLocally ) {
00964 uploadFlags();
00965 break;
00966 } else {
00967
00968 }
00969 } else if ( mUserRights & KMail::ACLJobs::WriteSeenFlag ) {
00970 if ( !mUIDsOfLocallyChangedStatuses.empty() || 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.find( msg->UID() ) == mUIDsOfLocallyChangedStatuses.end()
01425 && !mStatusChangedLocally ) {
01426
01427 continue;
01428 }
01429
01430 QString flags = KMFolderImap::statusToFlags(msg->status(), mPermanentFlags);
01431
01432 QString uid;
01433 uid.setNum( msg->UID() );
01434 groups[flags].append(uid);
01435 }
01436 QMapIterator< QString, QStringList > dit;
01437 for( dit = groups.begin(); dit != groups.end(); ++dit ) {
01438 QCString flags = dit.key().latin1();
01439 QStringList sets = KMFolderImap::makeSets( (*dit), true );
01440 mStatusFlagsJobs += sets.count();
01441
01442 for( QStringList::Iterator slit = sets.begin(); slit != sets.end(); ++slit ) {
01443 QString imappath = imapPath() + ";UID=" + ( *slit );
01444 mAccount->setImapStatus(folder(), imappath, flags);
01445 }
01446 }
01447
01448
01449 if ( mStatusFlagsJobs ) {
01450 connect( mAccount, SIGNAL( imapStatusChanged(KMFolder*, const QString&, bool) ),
01451 this, SLOT( slotImapStatusChanged(KMFolder*, const QString&, bool) ) );
01452 return;
01453 }
01454 }
01455 newState( mProgress, i18n("No messages to upload to server"));
01456 serverSyncInternal();
01457 }
01458
01459 void KMFolderCachedImap::uploadSeenFlags()
01460 {
01461 if ( !uidMap.isEmpty() ) {
01462 mStatusFlagsJobs = 0;
01463 newState( mProgress, i18n("Uploading status of messages to server"));
01464
01465 QValueList<ulong> seenUids, unseenUids;
01466 for( int i = 0; i < count(); ++i ) {
01467 KMMsgBase* msg = getMsgBase( i );
01468 if( !msg || msg->UID() == 0 )
01469
01470 continue;
01471
01472 if ( mUIDsOfLocallyChangedStatuses.find( msg->UID() ) == mUIDsOfLocallyChangedStatuses.end()
01473 && !mStatusChangedLocally ) {
01474
01475 continue;
01476 }
01477
01478 if ( msg->status() & KMMsgStatusOld || msg->status() & KMMsgStatusRead )
01479 seenUids.append( msg->UID() );
01480 else
01481 unseenUids.append( msg->UID() );
01482 }
01483 if ( !seenUids.isEmpty() ) {
01484 QStringList sets = KMFolderImap::makeSets( seenUids, true );
01485 mStatusFlagsJobs += sets.count();
01486 for( QStringList::Iterator it = sets.begin(); it != sets.end(); ++it ) {
01487 QString imappath = imapPath() + ";UID=" + ( *it );
01488 mAccount->setImapSeenStatus( folder(), imappath, true );
01489 }
01490 }
01491 if ( !unseenUids.isEmpty() ) {
01492 QStringList sets = KMFolderImap::makeSets( unseenUids, true );
01493 mStatusFlagsJobs += sets.count();
01494 for( QStringList::Iterator it = sets.begin(); it != sets.end(); ++it ) {
01495 QString imappath = imapPath() + ";UID=" + ( *it );
01496 mAccount->setImapSeenStatus( folder(), imappath, false );
01497 }
01498 }
01499
01500 if ( mStatusFlagsJobs ) {
01501 connect( mAccount, SIGNAL( imapStatusChanged(KMFolder*, const QString&, bool) ),
01502 this, SLOT( slotImapStatusChanged(KMFolder*, const QString&, bool) ) );
01503 return;
01504 }
01505 }
01506 newState( mProgress, i18n("No messages to upload to server"));
01507 serverSyncInternal();
01508 }
01509
01510 void KMFolderCachedImap::slotImapStatusChanged(KMFolder* folder, const QString&, bool cont)
01511 {
01512 if ( mSyncState == SYNC_STATE_INITIAL ){
01513
01514 return;
01515 }
01516
01517 if ( folder->storage() == this ) {
01518 --mStatusFlagsJobs;
01519 if ( mStatusFlagsJobs == 0 || !cont )
01520 disconnect( mAccount, SIGNAL( imapStatusChanged(KMFolder*, const QString&, bool) ),
01521 this, SLOT( slotImapStatusChanged(KMFolder*, const QString&, bool) ) );
01522 if ( mStatusFlagsJobs == 0 && cont ) {
01523 mProgress += 5;
01524 serverSyncInternal();
01525
01526 }
01527 }
01528 }
01529
01530
01531 void KMFolderCachedImap::setStatus( int idx, KMMsgStatus status, bool toggle)
01532 {
01533 KMFolderMaildir::setStatus( idx, status, toggle );
01534 const KMMsgBase *msg = getMsgBase( idx );
01535 Q_ASSERT( msg );
01536 if ( msg )
01537 mUIDsOfLocallyChangedStatuses.insert( msg->UID() );
01538 }
01539
01540 void KMFolderCachedImap::setStatus(QValueList<int>& ids, KMMsgStatus status, bool toggle)
01541 {
01542 KMFolderMaildir::setStatus(ids, status, toggle);
01543 for (QValueList<int>::iterator it = ids.begin(); it != ids.end(); it++ ) {
01544 const KMMsgBase *msg = getMsgBase( *it );
01545 Q_ASSERT( msg );
01546 if ( msg )
01547 mUIDsOfLocallyChangedStatuses.insert( msg->UID() );
01548 }
01549 }
01550
01551
01552 void KMFolderCachedImap::createNewFolders()
01553 {
01554 QValueList<KMFolderCachedImap*> newFolders = findNewFolders();
01555
01556 if( !newFolders.isEmpty() ) {
01557 newState( mProgress, i18n("Creating subfolders on server"));
01558 CachedImapJob *job = new CachedImapJob( newFolders, CachedImapJob::tAddSubfolders, this );
01559 connect( job, SIGNAL( result(KMail::FolderJob *) ), this, SLOT( slotIncreaseProgress() ) );
01560 connect( job, SIGNAL( finished() ), this, SLOT( serverSyncInternal() ) );
01561 job->start();
01562 } else {
01563 serverSyncInternal();
01564 }
01565 }
01566
01567 QValueList<KMFolderCachedImap*> KMFolderCachedImap::findNewFolders()
01568 {
01569 QValueList<KMFolderCachedImap*> newFolders;
01570 if( folder() && folder()->child() ) {
01571 KMFolderNode *node = folder()->child()->first();
01572 while( node ) {
01573 if( !node->isDir() ) {
01574 if( static_cast<KMFolder*>(node)->folderType() != KMFolderTypeCachedImap ) {
01575 kdError(5006) << "KMFolderCachedImap::findNewFolders(): ARGH!!! "
01576 << node->name() << " is not an IMAP folder\n";
01577 node = folder()->child()->next();
01578 assert(0);
01579 }
01580 KMFolderCachedImap* folder = static_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage());
01581 if( folder->imapPath().isEmpty() ) {
01582 newFolders << folder;
01583 }
01584 }
01585 node = folder()->child()->next();
01586 }
01587 }
01588 return newFolders;
01589 }
01590
01591 bool KMFolderCachedImap::deleteMessages()
01592 {
01593
01594 QPtrList<KMMessage> msgsForDeletion;
01595
01596
01597
01598
01599
01600 QStringList uids;
01601 QMap<ulong,int>::const_iterator it = uidMap.constBegin();
01602 for( ; it != uidMap.end(); it++ ) {
01603 ulong uid ( it.key() );
01604 if( uid!=0 && !uidsOnServer.find( uid ) ) {
01605 uids << QString::number( uid );
01606 msgsForDeletion.append( getMsg( *it ) );
01607 }
01608 }
01609
01610 if( !msgsForDeletion.isEmpty() ) {
01611 #if MAIL_LOSS_DEBUGGING
01612 if ( KMessageBox::warningYesNo(
01613 0, i18n( "<qt><p>Mails on the server in folder <b>%1</b> were deleted. "
01614 "Do you want to delete them locally?<br>UIDs: %2</p></qt>" )
01615 .arg( folder()->prettyURL() ).arg( uids.join(",") ) ) == KMessageBox::Yes )
01616 #endif
01617 removeMsg( msgsForDeletion );
01618 }
01619
01620 if ( mUserRights > 0 && !( mUserRights & KMail::ACLJobs::Delete ) )
01621 return false;
01622
01623
01624 if( !uidsForDeletionOnServer.isEmpty() ) {
01625 newState( mProgress, i18n("Deleting removed messages from server"));
01626 QStringList sets = KMFolderImap::makeSets( uidsForDeletionOnServer, true );
01627 uidsForDeletionOnServer.clear();
01628 kdDebug(5006) << "Deleting " << sets.count() << " sets of messages from server folder " << imapPath() << endl;
01629 CachedImapJob *job = new CachedImapJob( sets, CachedImapJob::tDeleteMessage, this );
01630 connect( job, SIGNAL( result(KMail::FolderJob *) ),
01631 this, SLOT( slotDeleteMessagesResult(KMail::FolderJob *) ) );
01632 job->start();
01633 return true;
01634 } else {
01635 return false;
01636 }
01637 }
01638
01639 void KMFolderCachedImap::slotDeleteMessagesResult( KMail::FolderJob* job )
01640 {
01641 if ( job->error() ) {
01642
01643 mSyncState = SYNC_STATE_GET_MESSAGES;
01644 } else {
01645
01646 mDeletedUIDsSinceLastSync.clear();
01647 }
01648 mProgress += 10;
01649 serverSyncInternal();
01650 }
01651
01652 void KMFolderCachedImap::checkUidValidity() {
01653
01654
01655 if( imapPath().isEmpty() || imapPath() == "/" )
01656
01657 serverSyncInternal();
01658 else {
01659 newState( mProgress, i18n("Checking folder validity"));
01660 CachedImapJob *job = new CachedImapJob( FolderJob::tCheckUidValidity, this );
01661 connect( job, SIGNAL(permanentFlags(int)), SLOT(slotPermanentFlags(int)) );
01662 connect( job, SIGNAL( result( KMail::FolderJob* ) ),
01663 this, SLOT( slotCheckUidValidityResult( KMail::FolderJob* ) ) );
01664 job->start();
01665 }
01666 }
01667
01668 void KMFolderCachedImap::slotCheckUidValidityResult( KMail::FolderJob* job )
01669 {
01670 if ( job->error() ) {
01671
01672
01673 mSyncState = SYNC_STATE_HANDLE_INBOX;
01674 }
01675 mProgress += 5;
01676 serverSyncInternal();
01677 }
01678
01679 void KMFolderCachedImap::slotPermanentFlags(int flags)
01680 {
01681 mPermanentFlags = flags;
01682 }
01683
01684
01685
01686 void KMFolderCachedImap::listMessages() {
01687 bool groupwareOnly = GlobalSettings::self()->showOnlyGroupwareFoldersForGroupwareAccount()
01688 && GlobalSettings::self()->theIMAPResourceAccount() == (int)mAccount->id()
01689 && folder()->isSystemFolder()
01690 && mImapPath == "/INBOX/";
01691
01692
01693 if( imapPath() == "/" || groupwareOnly ) {
01694 serverSyncInternal();
01695 return;
01696 }
01697
01698 if( !mAccount->slave() ) {
01699 resetSyncState();
01700 emit folderComplete( this, false );
01701 return;
01702 }
01703 uidsOnServer.clear();
01704 uidsOnServer.resize( count() * 2 );
01705 uidsForDeletionOnServer.clear();
01706 mMsgsForDownload.clear();
01707 mUidsForDownload.clear();
01708
01709 mFoundAnIMAPDigest = false;
01710
01711 CachedImapJob* job = new CachedImapJob( FolderJob::tListMessages, this );
01712 connect( job, SIGNAL( result(KMail::FolderJob *) ),
01713 this, SLOT( slotGetLastMessagesResult(KMail::FolderJob *) ) );
01714 job->start();
01715 }
01716
01717 void KMFolderCachedImap::slotGetLastMessagesResult(KMail::FolderJob *job)
01718 {
01719 getMessagesResult(job, true);
01720 }
01721
01722
01723 void KMFolderCachedImap::slotGetMessagesData(KIO::Job * job, const QByteArray & data)
01724 {
01725 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
01726 if ( it == mAccount->jobsEnd() ) {
01727 kdDebug(5006) << "could not find job!?!?!" << endl;
01728
01729
01730
01731 mSyncState = SYNC_STATE_HANDLE_INBOX;
01732 serverSyncInternal();
01733 return;
01734 }
01735 (*it).cdata += QCString(data, data.size() + 1);
01736 int pos = (*it).cdata.find("\r\n--IMAPDIGEST");
01737 if (pos > 0) {
01738 int a = (*it).cdata.find("\r\nX-uidValidity:");
01739 if (a != -1) {
01740 int b = (*it).cdata.find("\r\n", a + 17);
01741 setUidValidity((*it).cdata.mid(a + 17, b - a - 17));
01742 }
01743 a = (*it).cdata.find("\r\nX-Access:");
01744
01745
01746
01747
01748
01749 if (a != -1 && mUserRights == -1 ) {
01750 int b = (*it).cdata.find("\r\n", a + 12);
01751 const QString access = (*it).cdata.mid(a + 12, b - a - 12);
01752 setReadOnly( access == "Read only" );
01753 }
01754 (*it).cdata.remove(0, pos);
01755 mFoundAnIMAPDigest = true;
01756 }
01757 pos = (*it).cdata.find("\r\n--IMAPDIGEST", 1);
01758
01759 if ( uidsOnServer.size() == 0 )
01760 uidsOnServer.resize( KMail::nextPrime( 2000 ) );
01761 const int v = 42;
01762 while (pos >= 0) {
01763
01764
01765
01766
01767
01768
01769
01770
01771
01772 const QCString& entry( (*it).cdata );
01773 const int indexOfUID = entry.find("X-UID", 16);
01774 const int startOfUIDValue = indexOfUID + 7;
01775 const int indexOfLength = entry.find("X-Length", startOfUIDValue );
01776 const int startOfLengthValue = indexOfLength + 10;
01777 const int indexOfFlags = entry.find("X-Flags", startOfLengthValue );
01778 const int startOfFlagsValue = indexOfFlags + 9;
01779
01780 const int flags = entry.mid( startOfFlagsValue, entry.find( '\r', startOfFlagsValue ) - startOfFlagsValue ).toInt();
01781 const ulong size = entry.mid( startOfLengthValue, entry.find( '\r', startOfLengthValue ) - startOfLengthValue ).toULong();
01782 const ulong uid = entry.mid( startOfUIDValue, entry.find( '\r', startOfUIDValue ) - startOfUIDValue ).toULong();
01783
01784 const bool deleted = ( flags & 8 );
01785 if ( !deleted ) {
01786 if( uid != 0 ) {
01787 if ( uidsOnServer.count() == uidsOnServer.size() ) {
01788 uidsOnServer.resize( KMail::nextPrime( uidsOnServer.size() * 2 ) );
01789
01790 }
01791 uidsOnServer.insert( uid, &v );
01792 }
01793 bool redownload = false;
01794 if ( uid <= lastUid() ) {
01795
01796
01797
01798
01799
01800
01801
01802
01803
01804
01805 KMMsgBase *existingMessage = findByUID(uid);
01806 if( !existingMessage ) {
01807 #if MAIL_LOSS_DEBUGGING
01808 kdDebug(5006) << "Looking at uid " << uid << " high water is: " << lastUid() << " we should delete it" << endl;
01809 #endif
01810
01811 if ( mDeletedUIDsSinceLastSync.contains(uid) ) {
01812 if ( mUserRights <= 0 || ( mUserRights & KMail::ACLJobs::Delete ) ) {
01813 #if MAIL_LOSS_DEBUGGING
01814 kdDebug(5006) << "message with uid " << uid << " is gone from local cache. Must be deleted on server!!!" << endl;
01815 #endif
01816 uidsForDeletionOnServer << uid;
01817 } else {
01818 redownload = true;
01819 }
01820 } else {
01821 kdDebug(5006) << "WARNING: ####### " << endl;
01822 kdDebug(5006) << "Message locally missing but not deleted in folder: " << folder()->prettyURL() << endl;
01823 kdDebug(5006) << "The missing UID: " << uid << ". It will be redownloaded " << endl;
01824 redownload = true;
01825 }
01826
01827 } else {
01828
01829
01830
01831 if ( !mReadOnly || !GlobalSettings::allowLocalFlags() ) {
01832
01833 KMFolderImap::flagsToStatus( existingMessage, flags, false, mReadOnly ? INT_MAX : mPermanentFlags );
01834 } else if ( mUserRights & KMail::ACLJobs::WriteSeenFlag ) {
01835 KMFolderImap::seenFlagToStatus( existingMessage, flags );
01836 }
01837 }
01838
01839 }
01840 if ( uid > lastUid() || redownload ) {
01841 #if MAIL_LOSS_DEBUGGING
01842 kdDebug(5006) << "Looking at uid " << uid << " high water is: " << lastUid() << " we should download it" << endl;
01843 #endif
01844
01845
01846 if ( !uidMap.contains( uid ) ) {
01847 mMsgsForDownload << KMail::CachedImapJob::MsgForDownload(uid, flags, size);
01848 if( imapPath() == "/INBOX/" )
01849 mUidsForDownload << uid;
01850 }
01851
01852 if ( uid > mTentativeHighestUid ) {
01853 #if MAIL_LOSS_DEBUGGING
01854 kdDebug(5006) << "Setting the tentative highest UID to: " << uid << endl;
01855 #endif
01856 mTentativeHighestUid = uid;
01857 }
01858 }
01859 }
01860 (*it).cdata.remove(0, pos);
01861 (*it).done++;
01862 pos = (*it).cdata.find("\r\n--IMAPDIGEST", 1);
01863 }
01864 }
01865
01866 void KMFolderCachedImap::getMessagesResult( KMail::FolderJob *job, bool lastSet )
01867 {
01868 mProgress += 10;
01869 if ( !job->error() && !mFoundAnIMAPDigest ) {
01870 kdWarning(5006) << "######## Folderlisting did not complete, but there was no error! "
01871 "Aborting sync of folder: " << folder()->prettyURL() << endl;
01872 #if MAIL_LOSS_DEBUGGING
01873 kmkernel->emergencyExit( i18n("Folder listing failed in interesting ways." ) );
01874 #endif
01875 }
01876 if( job->error() ) {
01877 mContentState = imapNoInformation;
01878 mSyncState = SYNC_STATE_HANDLE_INBOX;
01879 } else {
01880 if( lastSet ) {
01881 mContentState = imapFinished;
01882 mUIDsOfLocallyChangedStatuses.clear();
01883 mStatusChangedLocally = false;
01884 }
01885 }
01886 serverSyncInternal();
01887 }
01888
01889 void KMFolderCachedImap::slotProgress(unsigned long done, unsigned long total)
01890 {
01891 int progressSpan = 100 - 5 - mProgress;
01892
01893
01894
01895 newState( mProgress + (progressSpan * done) / total, QString::null );
01896 }
01897
01898 void KMFolderCachedImap::setAccount(KMAcctCachedImap *aAccount)
01899 {
01900 assert( aAccount->isA("KMAcctCachedImap") );
01901 mAccount = aAccount;
01902 if( imapPath()=="/" ) aAccount->setFolder( folder() );
01903
01904
01905 QString newName = mAccount->renamedFolder( imapPath() );
01906 if ( !newName.isEmpty() )
01907 folder()->setLabel( newName );
01908
01909 if( !folder() || !folder()->child() || !folder()->child()->count() ) return;
01910 for( KMFolderNode* node = folder()->child()->first(); node;
01911 node = folder()->child()->next() )
01912 if (!node->isDir())
01913 static_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage())->setAccount(aAccount);
01914 }
01915
01916 void KMFolderCachedImap::listNamespaces()
01917 {
01918 ImapAccountBase::ListType type = ImapAccountBase::List;
01919 if ( mAccount->onlySubscribedFolders() )
01920 type = ImapAccountBase::ListSubscribed;
01921
01922 kdDebug(5006) << "listNamespaces " << mNamespacesToList << endl;
01923 if ( mNamespacesToList.isEmpty() ) {
01924 mSyncState = SYNC_STATE_DELETE_SUBFOLDERS;
01925 mPersonalNamespacesCheckDone = true;
01926
01927 QStringList ns = mAccount->namespaces()[ImapAccountBase::OtherUsersNS];
01928 ns += mAccount->namespaces()[ImapAccountBase::SharedNS];
01929 mNamespacesToCheck = ns.count();
01930 for ( QStringList::Iterator it = ns.begin(); it != ns.end(); ++it )
01931 {
01932 if ( (*it).isEmpty() ) {
01933
01934 --mNamespacesToCheck;
01935 continue;
01936 }
01937 KMail::ListJob* job = new KMail::ListJob( mAccount, type, this, mAccount->addPathToNamespace( *it ) );
01938 job->setHonorLocalSubscription( true );
01939 connect( job, SIGNAL(receivedFolders(const QStringList&, const QStringList&,
01940 const QStringList&, const QStringList&, const ImapAccountBase::jobData&)),
01941 this, SLOT(slotCheckNamespace(const QStringList&, const QStringList&,
01942 const QStringList&, const QStringList&, const ImapAccountBase::jobData&)));
01943 job->start();
01944 }
01945 if ( mNamespacesToCheck == 0 ) {
01946 serverSyncInternal();
01947 }
01948 return;
01949 }
01950 mPersonalNamespacesCheckDone = false;
01951
01952 QString ns = mNamespacesToList.front();
01953 mNamespacesToList.pop_front();
01954
01955 mSyncState = SYNC_STATE_LIST_SUBFOLDERS2;
01956 newState( mProgress, i18n("Retrieving folders for namespace %1").arg(ns));
01957 KMail::ListJob* job = new KMail::ListJob( mAccount, type, this,
01958 mAccount->addPathToNamespace( ns ) );
01959 job->setNamespace( ns );
01960 job->setHonorLocalSubscription( true );
01961 connect( job, SIGNAL(receivedFolders(const QStringList&, const QStringList&,
01962 const QStringList&, const QStringList&, const ImapAccountBase::jobData&)),
01963 this, SLOT(slotListResult(const QStringList&, const QStringList&,
01964 const QStringList&, const QStringList&, const ImapAccountBase::jobData&)));
01965 job->start();
01966 }
01967
01968 void KMFolderCachedImap::slotCheckNamespace( const QStringList& subfolderNames,
01969 const QStringList& subfolderPaths,
01970 const QStringList& subfolderMimeTypes,
01971 const QStringList& subfolderAttributes,
01972 const ImapAccountBase::jobData& jobData )
01973 {
01974 Q_UNUSED( subfolderPaths );
01975 Q_UNUSED( subfolderMimeTypes );
01976 Q_UNUSED( subfolderAttributes );
01977 --mNamespacesToCheck;
01978 kdDebug(5006) << "slotCheckNamespace " << subfolderNames << ",remain=" <<
01979 mNamespacesToCheck << endl;
01980
01981
01982
01983 QString name = jobData.path.mid( 1, jobData.path.length()-2 );
01984 name.remove( mAccount->delimiterForNamespace( name ) );
01985 if ( name.isEmpty() ) {
01986
01987 kdWarning(5006) << "slotCheckNamespace: ignoring empty folder!" << endl;
01988 return;
01989 }
01990
01991 folder()->createChildFolder();
01992 KMFolderNode *node = 0;
01993 for ( node = folder()->child()->first(); node;
01994 node = folder()->child()->next())
01995 {
01996 if ( !node->isDir() && node->name() == name )
01997 break;
01998 }
01999 if ( !subfolderNames.isEmpty() ) {
02000 if ( node ) {
02001
02002 kdDebug(5006) << "found namespace folder " << name << endl;
02003 } else
02004 {
02005
02006 kdDebug(5006) << "create namespace folder " << name << endl;
02007 KMFolder* newFolder = folder()->child()->createFolder( name, false,
02008 KMFolderTypeCachedImap );
02009 if ( newFolder ) {
02010 KMFolderCachedImap *f = static_cast<KMFolderCachedImap*>( newFolder->storage() );
02011 f->setImapPath( mAccount->addPathToNamespace( name ) );
02012 f->setNoContent( true );
02013 f->setAccount( mAccount );
02014 f->close("cachedimap");
02015 kmkernel->dimapFolderMgr()->contentsChanged();
02016 }
02017 }
02018 } else {
02019 if ( node ) {
02020 kdDebug(5006) << "delete namespace folder " << name << endl;
02021 KMFolder* fld = static_cast<KMFolder*>(node);
02022 kmkernel->dimapFolderMgr()->remove( fld );
02023 }
02024 }
02025
02026 if ( mNamespacesToCheck == 0 ) {
02027
02028 serverSyncInternal();
02029 }
02030 }
02031
02032
02033
02034 bool KMFolderCachedImap::listDirectory()
02035 {
02036 if( !mAccount->slave() ) {
02037 resetSyncState();
02038 emit folderComplete( this, false );
02039 return false;
02040 }
02041 mSubfolderState = imapInProgress;
02042
02043
02044 ImapAccountBase::ListType type = ImapAccountBase::List;
02045 if ( mAccount->onlySubscribedFolders() )
02046 type = ImapAccountBase::ListSubscribed;
02047 KMail::ListJob* job = new KMail::ListJob( mAccount, type, this );
02048 job->setHonorLocalSubscription( true );
02049 connect( job, SIGNAL(receivedFolders(const QStringList&, const QStringList&,
02050 const QStringList&, const QStringList&, const ImapAccountBase::jobData&)),
02051 this, SLOT(slotListResult(const QStringList&, const QStringList&,
02052 const QStringList&, const QStringList&, const ImapAccountBase::jobData&)));
02053 job->start();
02054
02055 return true;
02056 }
02057
02058 void KMFolderCachedImap::slotListResult( const QStringList& folderNames,
02059 const QStringList& folderPaths,
02060 const QStringList& folderMimeTypes,
02061 const QStringList& folderAttributes,
02062 const ImapAccountBase::jobData& jobData )
02063 {
02064 Q_UNUSED( jobData );
02065
02066
02067 mSubfolderNames = folderNames;
02068 mSubfolderPaths = folderPaths;
02069 mSubfolderMimeTypes = folderMimeTypes;
02070 mSubfolderState = imapFinished;
02071 mSubfolderAttributes = folderAttributes;
02072 kdDebug(5006) << "##### setting subfolder attributes: " << mSubfolderAttributes << endl;
02073
02074 folder()->createChildFolder();
02075 KMFolderNode *node = folder()->child()->first();
02076 bool root = ( this == mAccount->rootFolder() );
02077
02078 QPtrList<KMFolder> toRemove;
02079 bool emptyList = ( root && mSubfolderNames.empty() );
02080 if ( !emptyList ) {
02081 while (node) {
02082 if (!node->isDir() ) {
02083 KMFolderCachedImap *f = static_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage());
02084
02085 if ( mSubfolderNames.findIndex(node->name()) == -1 ) {
02086 QString name = node->name();
02087
02088
02089 bool isInNamespace = ( jobData.curNamespace.isEmpty() ||
02090 jobData.curNamespace == mAccount->namespaceForFolder( f ) );
02091
02092 bool ignore = root && ( f->imapPath() == "/INBOX/" ||
02093 mAccount->isNamespaceFolder( name ) || !isInNamespace );
02094
02095
02096 if( !f->imapPath().isEmpty() && !ignore ) {
02097
02098
02099 toRemove.append( f->folder() );
02100 kdDebug(5006) << node->name() << " isn't on the server. It has an imapPath -> delete it locally" << endl;
02101 }
02102 } else {
02103
02104
02108 int index = mSubfolderNames.findIndex( node->name() );
02109 f->mFolderAttributes = folderAttributes[ index ];
02110 }
02111 } else {
02112
02113 }
02114 node = folder()->child()->next();
02115 }
02116 }
02117
02118 for ( KMFolder* doomed=toRemove.first(); doomed; doomed = toRemove.next() ) {
02119 rescueUnsyncedMessagesAndDeleteFolder( doomed );
02120 }
02121
02122 mProgress += 5;
02123
02124
02125 slotRescueDone( 0 );
02126 }
02127
02128
02129 void KMFolderCachedImap::listDirectory2()
02130 {
02131 QString path = folder()->path();
02132 kmkernel->dimapFolderMgr()->quiet(true);
02133
02134 bool root = ( this == mAccount->rootFolder() );
02135 if ( root && !mAccount->hasInbox() )
02136 {
02137 KMFolderCachedImap *f = 0;
02138 KMFolderNode *node;
02139
02140 for (node = folder()->child()->first(); node; node = folder()->child()->next())
02141 if (!node->isDir() && node->name() == "INBOX") break;
02142 if (node) {
02143 f = static_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage());
02144 } else {
02145 KMFolder* newFolder = folder()->child()->createFolder("INBOX", true, KMFolderTypeCachedImap);
02146 if ( newFolder ) {
02147 f = static_cast<KMFolderCachedImap*>(newFolder->storage());
02148 }
02149 }
02150 if ( f ) {
02151 f->setAccount( mAccount );
02152 f->setImapPath( "/INBOX/" );
02153 f->folder()->setLabel( i18n("inbox") );
02154 }
02155 if (!node) {
02156 if ( f )
02157 f->close("cachedimap");
02158 kmkernel->dimapFolderMgr()->contentsChanged();
02159 }
02160
02161 mAccount->setHasInbox( true );
02162 }
02163
02164 if ( root && !mSubfolderNames.isEmpty() ) {
02165 KMFolderCachedImap* parent =
02166 findParent( mSubfolderPaths.first(), mSubfolderNames.first() );
02167 if ( parent ) {
02168 kdDebug(5006) << "KMFolderCachedImap::listDirectory2 - pass listing to "
02169 << parent->label() << endl;
02170 mSubfolderNames.clear();
02171 }
02172 }
02173
02174
02175 QValueVector<int> foldersNewOnServer;
02176 for (uint i = 0; i < mSubfolderNames.count(); i++) {
02177
02178
02179 KMFolderCachedImap *f = 0;
02180 KMFolderNode *node = 0;
02181 for (node = folder()->child()->first(); node;
02182 node = folder()->child()->next())
02183 if (!node->isDir() && node->name() == mSubfolderNames[i]) break;
02184
02185 if (!node) {
02186
02187
02188 QString subfolderPath = mSubfolderPaths[i];
02189
02190
02191
02192 bool locallyDeleted = mAccount->isDeletedFolder( subfolderPath );
02193
02194
02195
02196 if ( !locallyDeleted && mAccount->isPreviouslyDeletedFolder( subfolderPath ) ) {
02197 locallyDeleted = KMessageBox::warningYesNo(
02198 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;
02199 }
02200
02201 if ( locallyDeleted ) {
02202 kdDebug(5006) << subfolderPath << " was deleted locally => delete on server." << endl;
02203 foldersForDeletionOnServer += mAccount->deletedFolderPaths( subfolderPath );
02204 } else {
02205 kdDebug(5006) << subfolderPath << " is a new folder on the server => create local cache" << endl;
02206 foldersNewOnServer.append( i );
02207 }
02208 } else {
02209 if( static_cast<KMFolder*>(node)->folderType() == KMFolderTypeCachedImap )
02210 f = dynamic_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage());
02211 if( f ) {
02212
02213
02214
02215 f->setAccount(mAccount);
02216 f->setNoContent(mSubfolderMimeTypes[i] == "inode/directory");
02217 f->setNoChildren(mSubfolderMimeTypes[i] == "message/digest");
02218 f->setImapPath(mSubfolderPaths[i]);
02219 }
02220 }
02221 }
02222
02223
02224
02225
02226
02227
02228
02229
02230
02231
02232
02233 if ( GlobalSettings::self()->showOnlyGroupwareFoldersForGroupwareAccount()
02234 && GlobalSettings::self()->theIMAPResourceAccount() == (int)mAccount->id()
02235 && mAccount->hasAnnotationSupport()
02236 && GlobalSettings::self()->theIMAPResourceEnabled()
02237 && !foldersNewOnServer.isEmpty() ) {
02238
02239 QStringList paths;
02240 for ( uint i = 0; i < foldersNewOnServer.count(); ++i )
02241 paths << mSubfolderPaths[ foldersNewOnServer[i] ];
02242
02243 AnnotationJobs::MultiUrlGetAnnotationJob* job =
02244 AnnotationJobs::multiUrlGetAnnotation( mAccount->slave(), mAccount->getUrl(), paths, KOLAB_FOLDERTYPE );
02245 ImapAccountBase::jobData jd( QString::null, folder() );
02246 jd.cancellable = true;
02247 mAccount->insertJob(job, jd);
02248 connect( job, SIGNAL(result(KIO::Job *)),
02249 SLOT(slotMultiUrlGetAnnotationResult(KIO::Job *)) );
02250
02251 } else {
02252 createFoldersNewOnServerAndFinishListing( foldersNewOnServer );
02253 }
02254 }
02255
02256 void KMFolderCachedImap::createFoldersNewOnServerAndFinishListing( const QValueVector<int> foldersNewOnServer )
02257 {
02258 for ( uint i = 0; i < foldersNewOnServer.count(); ++i ) {
02259 int idx = foldersNewOnServer[i];
02260 KMFolder* newFolder = folder()->child()->createFolder( mSubfolderNames[idx], false, KMFolderTypeCachedImap);
02261 if (newFolder) {
02262 KMFolderCachedImap *f = dynamic_cast<KMFolderCachedImap*>(newFolder->storage());
02263 kdDebug(5006) << " ####### Locally creating folder " << mSubfolderNames[idx] <<endl;
02264 f->close("cachedimap");
02265 f->setAccount(mAccount);
02266 f->mAnnotationFolderType = "FROMSERVER";
02267 f->setNoContent(mSubfolderMimeTypes[idx] == "inode/directory");
02268 f->setNoChildren(mSubfolderMimeTypes[idx] == "message/digest");
02269 f->setImapPath(mSubfolderPaths[idx]);
02270 f->mFolderAttributes = mSubfolderAttributes[idx];
02271 kdDebug(5006) << " ####### Attributes: " << f->mFolderAttributes <<endl;
02272
02273 kmkernel->dimapFolderMgr()->contentsChanged();
02274 } else {
02275 kdDebug(5006) << "can't create folder " << mSubfolderNames[idx] <<endl;
02276 }
02277 }
02278
02279 kmkernel->dimapFolderMgr()->quiet(false);
02280 emit listComplete(this);
02281 if ( !mPersonalNamespacesCheckDone ) {
02282
02283 mSyncState = SYNC_STATE_LIST_NAMESPACES;
02284 }
02285 serverSyncInternal();
02286 }
02287
02288
02289 KMFolderCachedImap* KMFolderCachedImap::findParent( const QString& path,
02290 const QString& name )
02291 {
02292 QString parent = path.left( path.length() - name.length() - 2 );
02293 if ( parent.length() > 1 )
02294 {
02295
02296 parent = parent.right( parent.length() - 1 );
02297 if ( parent != label() )
02298 {
02299 KMFolderNode *node = folder()->child()->first();
02300
02301 while ( node )
02302 {
02303 if ( node->name() == parent )
02304 {
02305 KMFolder* fld = static_cast<KMFolder*>(node);
02306 KMFolderCachedImap* imapFld =
02307 static_cast<KMFolderCachedImap*>( fld->storage() );
02308 return imapFld;
02309 }
02310 node = folder()->child()->next();
02311 }
02312 }
02313 }
02314 return 0;
02315 }
02316
02317 void KMFolderCachedImap::slotSubFolderComplete(KMFolderCachedImap* sub, bool success)
02318 {
02319 Q_UNUSED(sub);
02320
02321 if ( success ) {
02322 serverSyncInternal();
02323 }
02324 else
02325 {
02326
02327 if ( mCurrentSubfolder ) {
02328 Q_ASSERT( sub == mCurrentSubfolder );
02329 disconnect( mCurrentSubfolder, SIGNAL( folderComplete(KMFolderCachedImap*, bool) ),
02330 this, SLOT( slotSubFolderComplete(KMFolderCachedImap*, bool) ) );
02331 mCurrentSubfolder = 0;
02332 }
02333
02334 mSubfoldersForSync.clear();
02335 mSyncState = SYNC_STATE_INITIAL;
02336 close("cachedimap");
02337 emit folderComplete( this, false );
02338 }
02339 }
02340
02341 void KMFolderCachedImap::slotSimpleData(KIO::Job * job, const QByteArray & data)
02342 {
02343 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
02344 if (it == mAccount->jobsEnd()) return;
02345 QBuffer buff((*it).data);
02346 buff.open(IO_WriteOnly | IO_Append);
02347 buff.writeBlock(data.data(), data.size());
02348 buff.close();
02349 }
02350
02351 FolderJob*
02352 KMFolderCachedImap::doCreateJob( KMMessage *msg, FolderJob::JobType jt, KMFolder *folder,
02353 QString, const AttachmentStrategy* ) const
02354 {
02355 QPtrList<KMMessage> msgList;
02356 msgList.append( msg );
02357 CachedImapJob *job = new CachedImapJob( msgList, jt, folder? static_cast<KMFolderCachedImap*>( folder->storage() ):0 );
02358 job->setParentFolder( this );
02359 return job;
02360 }
02361
02362 FolderJob*
02363 KMFolderCachedImap::doCreateJob( QPtrList<KMMessage>& msgList, const QString& sets,
02364 FolderJob::JobType jt, KMFolder *folder ) const
02365 {
02366
02367 Q_UNUSED( sets );
02368 CachedImapJob *job = new CachedImapJob( msgList, jt, folder? static_cast<KMFolderCachedImap*>( folder->storage() ):0 );
02369 job->setParentFolder( this );
02370 return job;
02371 }
02372
02373 void
02374 KMFolderCachedImap::setUserRights( unsigned int userRights )
02375 {
02376 mUserRights = userRights;
02377 writeConfigKeysWhichShouldNotGetOverwrittenByReadConfig();
02378 }
02379
02380 void
02381 KMFolderCachedImap::slotReceivedUserRights( KMFolder* folder )
02382 {
02383 if ( folder->storage() == this ) {
02384 disconnect( mAccount, SIGNAL( receivedUserRights( KMFolder* ) ),
02385 this, SLOT( slotReceivedUserRights( KMFolder* ) ) );
02386 if ( mUserRights == 0 )
02387 mUserRights = -1;
02388 else
02389 setReadOnly( ( mUserRights & KMail::ACLJobs::Insert ) == 0 );
02390 mProgress += 5;
02391 serverSyncInternal();
02392 }
02393 }
02394
02395 void
02396 KMFolderCachedImap::setReadOnly( bool readOnly )
02397 {
02398 if ( readOnly != mReadOnly ) {
02399 mReadOnly = readOnly;
02400 emit readOnlyChanged( folder() );
02401 }
02402 }
02403
02404 void
02405 KMFolderCachedImap::slotReceivedACL( KMFolder* folder, KIO::Job*, const KMail::ACLList& aclList )
02406 {
02407 if ( folder->storage() == this ) {
02408 disconnect( mAccount, SIGNAL(receivedACL( KMFolder*, KIO::Job*, const KMail::ACLList& )),
02409 this, SLOT(slotReceivedACL( KMFolder*, KIO::Job*, const KMail::ACLList& )) );
02410 mACLList = aclList;
02411 serverSyncInternal();
02412 }
02413 }
02414
02415 void
02416 KMFolderCachedImap::slotStorageQuotaResult( const QuotaInfo& info )
02417 {
02418 setQuotaInfo( info );
02419 }
02420
02421 void KMFolderCachedImap::setQuotaInfo( const QuotaInfo & info )
02422 {
02423 if ( info != mQuotaInfo ) {
02424 mQuotaInfo = info;
02425 writeConfigKeysWhichShouldNotGetOverwrittenByReadConfig();
02426 emit folderSizeChanged();
02427 }
02428 }
02429
02430 void
02431 KMFolderCachedImap::setACLList( const ACLList& arr )
02432 {
02433 mACLList = arr;
02434 }
02435
02436 void
02437 KMFolderCachedImap::slotMultiSetACLResult(KIO::Job *job)
02438 {
02439 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
02440 if ( it == mAccount->jobsEnd() ) return;
02441 if ( (*it).parent != folder() ) return;
02442
02443 if ( job->error() )
02444
02445
02446 job->showErrorDialog();
02447 else
02448 kmkernel->iCalIface().addFolderChange( folder(), KMailICalIfaceImpl::ACL );
02449
02450 if (mAccount->slave()) mAccount->removeJob(job);
02451 serverSyncInternal();
02452 }
02453
02454 void
02455 KMFolderCachedImap::slotACLChanged( const QString& userId, int permissions )
02456 {
02457
02458
02459 for( ACLList::Iterator it = mACLList.begin(); it != mACLList.end(); ++it ) {
02460 if ( (*it).userId == userId && (*it).permissions == permissions ) {
02461 if ( permissions == -1 )
02462 mACLList.erase( it );
02463 else
02464 (*it).changed = false;
02465 return;
02466 }
02467 }
02468 }
02469
02470
02471 void KMFolderCachedImap::resetSyncState()
02472 {
02473 if ( mSyncState == SYNC_STATE_INITIAL ) return;
02474 mSubfoldersForSync.clear();
02475 mSyncState = SYNC_STATE_INITIAL;
02476 close("cachedimap");
02477
02478 KPIM::ProgressItem *progressItem = mAccount->mailCheckProgressItem();
02479 QString str = i18n("Aborted");
02480 if (progressItem)
02481 progressItem->setStatus( str );
02482 emit statusMsg( str );
02483 }
02484
02485 void KMFolderCachedImap::slotIncreaseProgress()
02486 {
02487 mProgress += 5;
02488 }
02489
02490 void KMFolderCachedImap::newState( int progress, const QString& syncStatus )
02491 {
02492
02493 KPIM::ProgressItem *progressItem = mAccount->mailCheckProgressItem();
02494 if( progressItem )
02495 progressItem->setCompletedItems( progress );
02496 if ( !syncStatus.isEmpty() ) {
02497 QString str;
02498
02499 if ( mAccount->imapFolder() == this )
02500 str = syncStatus;
02501 else
02502 str = QString( "%1: %2" ).arg( label() ).arg( syncStatus );
02503 if( progressItem )
02504 progressItem->setStatus( str );
02505 emit statusMsg( str );
02506 }
02507 if( progressItem )
02508 progressItem->updateProgress();
02509 }
02510
02511 void KMFolderCachedImap::setSubfolderState( imapState state )
02512 {
02513 mSubfolderState = state;
02514 if ( state == imapNoInformation && folder()->child() )
02515 {
02516
02517 KMFolderNode* node;
02518 QPtrListIterator<KMFolderNode> it( *folder()->child() );
02519 for ( ; (node = it.current()); )
02520 {
02521 ++it;
02522 if (node->isDir()) continue;
02523 KMFolder *folder = static_cast<KMFolder*>(node);
02524 static_cast<KMFolderCachedImap*>(folder->storage())->setSubfolderState( state );
02525 }
02526 }
02527 }
02528
02529 void KMFolderCachedImap::setImapPath(const QString &path)
02530 {
02531 mImapPath = path;
02532 }
02533
02534
02535
02536
02537
02538
02539 void KMFolderCachedImap::updateAnnotationFolderType()
02540 {
02541 QString oldType = mAnnotationFolderType;
02542 QString oldSubType;
02543 int dot = oldType.find( '.' );
02544 if ( dot != -1 ) {
02545 oldType.truncate( dot );
02546 oldSubType = mAnnotationFolderType.mid( dot + 1 );
02547 }
02548
02549 QString newType, newSubType;
02550
02551 if ( kmkernel->iCalIface().storageFormat( folder() ) == KMailICalIfaceImpl::StorageXML ) {
02552 newType = KMailICalIfaceImpl::annotationForContentsType( mContentsType );
02553 if ( kmkernel->iCalIface().isStandardResourceFolder( folder() ) )
02554 newSubType = "default";
02555 else if ( oldSubType != "default" )
02556 newSubType = oldSubType;
02557 }
02558
02559
02560 if ( newType != oldType || newSubType != oldSubType ) {
02561 mAnnotationFolderType = newType + ( newSubType.isEmpty() ? QString::null : "."+newSubType );
02562 mAnnotationFolderTypeChanged = true;
02563 kdDebug(5006) << mImapPath << ": updateAnnotationFolderType: '" << mAnnotationFolderType << "', was (" << oldType << " " << oldSubType << ") => mAnnotationFolderTypeChanged set to TRUE" << endl;
02564 }
02565
02566 writeConfigKeysWhichShouldNotGetOverwrittenByReadConfig();
02567 }
02568
02569 void KMFolderCachedImap::setIncidencesFor( IncidencesFor incfor )
02570 {
02571 if ( mIncidencesFor != incfor ) {
02572 mIncidencesFor = incfor;
02573 mIncidencesForChanged = true;
02574 }
02575 }
02576
02577 void KMFolderCachedImap::setSharedSeenFlags(bool b)
02578 {
02579 if ( mSharedSeenFlags != b ) {
02580 mSharedSeenFlags = b;
02581 mSharedSeenFlagsChanged = true;
02582 }
02583 }
02584
02585 void KMFolderCachedImap::slotAnnotationResult(const QString& entry, const QString& value, bool found)
02586 {
02587 if ( entry == KOLAB_FOLDERTYPE ) {
02588
02589
02590
02591
02592
02593 if ( found ) {
02594 QString type = value;
02595 QString subtype;
02596 int dot = value.find( '.' );
02597 if ( dot != -1 ) {
02598 type.truncate( dot );
02599 subtype = value.mid( dot + 1 );
02600 }
02601 bool foundKnownType = false;
02602 for ( uint i = 0 ; i <= ContentsTypeLast; ++i ) {
02603 FolderContentsType contentsType = static_cast<KMail::FolderContentsType>( i );
02604 if ( type == KMailICalIfaceImpl::annotationForContentsType( contentsType ) ) {
02605
02606
02607 if ( contentsType != ContentsTypeMail )
02608 kmkernel->iCalIface().setStorageFormat( folder(), KMailICalIfaceImpl::StorageXML );
02609 mAnnotationFolderType = value;
02610 if ( folder()->parent()->owner()->idString() != GlobalSettings::self()->theIMAPResourceFolderParent()
02611 && GlobalSettings::self()->theIMAPResourceEnabled()
02612 && subtype == "default" ) {
02613
02614
02615 mAnnotationFolderType = type;
02616 kdDebug(5006) << mImapPath << ": slotGetAnnotationResult: parent folder is " << folder()->parent()->owner()->idString() << " => truncating annotation to " << value << endl;
02617 }
02618 setContentsType( contentsType );
02619 mAnnotationFolderTypeChanged = false;
02620 foundKnownType = true;
02621
02622
02623
02624
02625
02626 if ( contentsType != ContentsTypeMail )
02627 markUnreadAsRead();
02628
02629
02630 writeConfigKeysWhichShouldNotGetOverwrittenByReadConfig();
02631 break;
02632 }
02633 }
02634 if ( !foundKnownType && !mReadOnly ) {
02635
02636
02637 mAnnotationFolderTypeChanged = true;
02638 }
02639
02640 }
02641 else if ( !mReadOnly ) {
02642
02643
02644 mAnnotationFolderTypeChanged = true;
02645 }
02646 } else if ( entry == KOLAB_INCIDENCESFOR ) {
02647 if ( found ) {
02648 mIncidencesFor = incidencesForFromString( value );
02649 Q_ASSERT( mIncidencesForChanged == false );
02650 }
02651 } else if ( entry == KOLAB_SHAREDSEEN ) {
02652 if ( found ) {
02653 mSharedSeenFlags = value == "true";
02654 }
02655 }
02656 }
02657
02658 void KMFolderCachedImap::slotGetAnnotationResult( KIO::Job* job )
02659 {
02660 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
02661 Q_ASSERT( it != mAccount->jobsEnd() );
02662 if ( it == mAccount->jobsEnd() ) return;
02663 Q_ASSERT( (*it).parent == folder() );
02664 if ( (*it).parent != folder() ) return;
02665
02666 AnnotationJobs::GetAnnotationJob* annjob = static_cast<AnnotationJobs::GetAnnotationJob *>( job );
02667 if ( annjob->error() ) {
02668 if ( job->error() == KIO::ERR_UNSUPPORTED_ACTION ) {
02669
02670 if ( GlobalSettings::self()->theIMAPResourceStorageFormat() == GlobalSettings::EnumTheIMAPResourceStorageFormat::XML
02671 && (uint)GlobalSettings::self()->theIMAPResourceAccount() == mAccount->id() )
02672 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() ) );
02673 mAccount->setHasNoAnnotationSupport();
02674 }
02675 else
02676 kdWarning(5006) << "slotGetAnnotationResult: " << job->errorString() << endl;
02677 }
02678
02679 if (mAccount->slave()) mAccount->removeJob(job);
02680 mProgress += 2;
02681 serverSyncInternal();
02682 }
02683
02684 void KMFolderCachedImap::slotMultiUrlGetAnnotationResult( KIO::Job* job )
02685 {
02686 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
02687 Q_ASSERT( it != mAccount->jobsEnd() );
02688 if ( it == mAccount->jobsEnd() ) return;
02689 Q_ASSERT( (*it).parent == folder() );
02690 if ( (*it).parent != folder() ) return;
02691
02692 QValueVector<int> folders;
02693 AnnotationJobs::MultiUrlGetAnnotationJob* annjob
02694 = static_cast<AnnotationJobs::MultiUrlGetAnnotationJob *>( job );
02695 if ( annjob->error() ) {
02696 if ( job->error() == KIO::ERR_UNSUPPORTED_ACTION ) {
02697
02698 if ( GlobalSettings::self()->theIMAPResourceStorageFormat() == GlobalSettings::EnumTheIMAPResourceStorageFormat::XML
02699 && (uint)GlobalSettings::self()->theIMAPResourceAccount() == mAccount->id() )
02700 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() ) );
02701 mAccount->setHasNoAnnotationSupport();
02702 }
02703 else
02704 kdWarning(5006) << "slotGetMultiUrlAnnotationResult: " << job->errorString() << endl;
02705 } else {
02706
02707 QMap<QString, QString> annotations = annjob->annotations();
02708 QMap<QString, QString>::Iterator it = annotations.begin();
02709 for ( ; it != annotations.end(); ++it ) {
02710 const QString folderPath = it.key();
02711 const QString annotation = it.data();
02712 kdDebug(5006) << k_funcinfo << "Folder: " << folderPath << " has type: " << annotation << endl;
02713
02714 QString type(annotation);
02715 int dot = annotation.find( '.' );
02716 if ( dot != -1 ) type.truncate( dot );
02717 type = type.simplifyWhiteSpace();
02718
02719 const int idx = mSubfolderPaths.findIndex( folderPath );
02720 const bool isNoContent = mSubfolderMimeTypes[idx] == "inode/directory";
02721 if ( ( isNoContent && type.isEmpty() )
02722 || ( !type.isEmpty() && type != KMailICalIfaceImpl::annotationForContentsType( ContentsTypeMail ) ) ) {
02723 folders.append( idx );
02724 kdDebug(5006) << k_funcinfo << " subscribing to: " << folderPath << endl;
02725 } else {
02726 kdDebug(5006) << k_funcinfo << " automatically unsubscribing from: " << folderPath << endl;
02727 mAccount->changeLocalSubscription( folderPath, false );
02728 }
02729 }
02730 }
02731
02732 if (mAccount->slave()) mAccount->removeJob(job);
02733 createFoldersNewOnServerAndFinishListing( folders );
02734 }
02735
02736 void KMFolderCachedImap::slotQuotaResult( KIO::Job* job )
02737 {
02738 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
02739 Q_ASSERT( it != mAccount->jobsEnd() );
02740 if ( it == mAccount->jobsEnd() ) return;
02741 Q_ASSERT( (*it).parent == folder() );
02742 if ( (*it).parent != folder() ) return;
02743
02744 QuotaJobs::GetStorageQuotaJob* quotajob = static_cast<QuotaJobs::GetStorageQuotaJob *>( job );
02745 QuotaInfo empty;
02746 if ( quotajob->error() ) {
02747 if ( job->error() == KIO::ERR_UNSUPPORTED_ACTION ) {
02748
02749 mAccount->setHasNoQuotaSupport();
02750 setQuotaInfo( empty );
02751 }
02752 else
02753 kdWarning(5006) << "slotGetQuotaResult: " << job->errorString() << endl;
02754 }
02755
02756 if (mAccount->slave()) mAccount->removeJob(job);
02757 mProgress += 2;
02758 serverSyncInternal();
02759 }
02760
02761 void
02762 KMFolderCachedImap::slotAnnotationChanged( const QString& entry, const QString& attribute, const QString& value )
02763 {
02764 Q_UNUSED( attribute );
02765 Q_UNUSED( value );
02766
02767 if ( entry == KOLAB_FOLDERTYPE )
02768 mAnnotationFolderTypeChanged = false;
02769 else if ( entry == KOLAB_INCIDENCESFOR ) {
02770 mIncidencesForChanged = false;
02771
02772
02773 kmkernel->iCalIface().addFolderChange( folder(), KMailICalIfaceImpl::ACL );
02774 } else if ( entry == KOLAB_SHAREDSEEN ) {
02775 mSharedSeenFlagsChanged = false;
02776 }
02777 }
02778
02779 void KMFolderCachedImap::slotTestAnnotationResult(KIO::Job *job)
02780 {
02781 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
02782 Q_ASSERT( it != mAccount->jobsEnd() );
02783 if ( it == mAccount->jobsEnd() ) return;
02784 Q_ASSERT( (*it).parent == folder() );
02785 if ( (*it).parent != folder() ) return;
02786
02787 mAccount->setAnnotationCheckPassed( true );
02788 if ( job->error() ) {
02789 kdDebug(5006) << "Test Annotation was not passed, disabling annotation support" << endl;
02790 mAccount->setHasNoAnnotationSupport( );
02791 } else {
02792 kdDebug(5006) << "Test Annotation was passed OK" << endl;
02793 }
02794 if (mAccount->slave()) mAccount->removeJob(job);
02795 serverSyncInternal();
02796 }
02797
02798 void
02799 KMFolderCachedImap::slotSetAnnotationResult(KIO::Job *job)
02800 {
02801 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
02802 if ( it == mAccount->jobsEnd() ) return;
02803 if ( (*it).parent != folder() ) return;
02804
02805 bool cont = true;
02806 if ( job->error() ) {
02807
02808 if ( job->error() == KIO::ERR_UNSUPPORTED_ACTION && contentsType() == ContentsTypeMail ) {
02809 if (mAccount->slave()) mAccount->removeJob(job);
02810 } else {
02811 cont = mAccount->handleJobError( job, i18n( "Error while setting annotation: " ) + '\n' );
02812 }
02813 } else {
02814 if (mAccount->slave()) mAccount->removeJob(job);
02815 }
02816 if ( cont )
02817 serverSyncInternal();
02818 }
02819
02820 void KMFolderCachedImap::slotUpdateLastUid()
02821 {
02822 if( mTentativeHighestUid != 0 ) {
02823
02824
02825
02826
02827
02828
02829
02830
02831
02832
02833
02834 bool sane = count() == 0;
02835
02836 for (int i=0;i<count(); i++ ) {
02837 ulong uid = getMsgBase(i)->UID();
02838 if ( uid > mTentativeHighestUid && uid > lastUid() ) {
02839 kdWarning(5006) << "DANGER: Either the server listed a wrong highest uid, "
02840 "or we parsed it wrong. Send email to adam@kde.org, please, and include this log." << endl;
02841 kdWarning(5006) << "uid: " << uid << " mTentativeHighestUid: " << mTentativeHighestUid << endl;
02842 assert( false );
02843 break;
02844 } else {
02845 sane = true;
02846 }
02847 }
02848 if (sane) {
02849 #if MAIL_LOSS_DEBUGGING
02850 kdDebug(5006) << "Tentative highest UID test was sane, writing out: " << mTentativeHighestUid << endl;
02851 #endif
02852 setLastUid( mTentativeHighestUid );
02853 }
02854 }
02855 mTentativeHighestUid = 0;
02856 }
02857
02858 bool KMFolderCachedImap::isMoveable() const
02859 {
02860 return ( hasChildren() == HasNoChildren &&
02861 !folder()->isSystemFolder() ) ? true : false;
02862 }
02863
02864 void KMFolderCachedImap::slotFolderDeletionOnServerFinished()
02865 {
02866 for ( QStringList::const_iterator it = foldersForDeletionOnServer.constBegin();
02867 it != foldersForDeletionOnServer.constEnd(); ++it ) {
02868 KURL url( mAccount->getUrl() );
02869 url.setPath( *it );
02870 kmkernel->iCalIface().folderDeletedOnServer( url );
02871 }
02872 serverSyncInternal();
02873 }
02874
02875 int KMFolderCachedImap::createIndexFromContentsRecursive()
02876 {
02877 if ( !folder() || !folder()->child() )
02878 return 0;
02879
02880 KMFolderNode *node = 0;
02881 for( QPtrListIterator<KMFolderNode> it( *folder()->child() ); (node = it.current()); ++it ) {
02882 if( !node->isDir() ) {
02883 KMFolderCachedImap* storage = static_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage());
02884 kdDebug() << k_funcinfo << "Re-indexing: " << storage->folder()->label() << endl;
02885 int rv = storage->createIndexFromContentsRecursive();
02886 if ( rv > 0 )
02887 return rv;
02888 }
02889 }
02890
02891 return createIndexFromContents();
02892 }
02893
02894 void KMFolderCachedImap::setAlarmsBlocked( bool blocked )
02895 {
02896 mAlarmsBlocked = blocked;
02897 }
02898
02899 bool KMFolderCachedImap::alarmsBlocked() const
02900 {
02901 return mAlarmsBlocked;
02902 }
02903
02904 bool KMFolderCachedImap::isCloseToQuota() const
02905 {
02906 bool closeToQuota = false;
02907 if ( mQuotaInfo.isValid() && mQuotaInfo.max().toInt() > 0 ) {
02908 const int ratio = mQuotaInfo.current().toInt() * 100 / mQuotaInfo.max().toInt();
02909
02910 closeToQuota = ( ratio > 0 && ratio >= GlobalSettings::closeToQuotaThreshold() );
02911 }
02912
02913 return closeToQuota;
02914 }
02915
02916 KMCommand* KMFolderCachedImap::rescueUnsyncedMessages()
02917 {
02918 QValueList<unsigned long> newMsgs = findNewMessages();
02919 kdDebug() << k_funcinfo << newMsgs << " of " << count() << endl;
02920 if ( newMsgs.isEmpty() )
02921 return 0;
02922 KMFolder *dest = 0;
02923 bool manualMove = true;
02924 while ( GlobalSettings::autoLostFoundMove() ) {
02925
02926 KMFolder *inboxFolder = kmkernel->findFolderById( QString(".%1.directory/INBOX").arg( account()->id() ) );
02927 if ( !inboxFolder ) {
02928 kdWarning(5006) << k_funcinfo << "inbox not found!" << endl;
02929 break;
02930 }
02931 KMFolderDir *inboxDir = inboxFolder->child();
02932 if ( !inboxDir && !inboxFolder->storage() )
02933 break;
02934 assert( inboxFolder->storage()->folderType() == KMFolderTypeCachedImap );
02935
02936
02937 KMFolderNode *node;
02938 KMFolder *lfFolder = 0;
02939 if ( !(node = inboxDir->hasNamedFolder( i18n("lost+found") )) ) {
02940 kdDebug(5006) << k_funcinfo << "creating lost+found folder" << endl;
02941 KMFolder* folder = kmkernel->dimapFolderMgr()->createFolder(
02942 i18n("lost+found"), false, KMFolderTypeCachedImap, inboxDir );
02943 if ( !folder || !folder->storage() )
02944 break;
02945 static_cast<KMFolderCachedImap*>( folder->storage() )->initializeFrom(
02946 static_cast<KMFolderCachedImap*>( inboxFolder->storage() ) );
02947 folder->storage()->setContentsType( KMail::ContentsTypeMail );
02948 folder->storage()->writeConfig();
02949 lfFolder = folder;
02950 } else {
02951 kdDebug(5006) << k_funcinfo << "found lost+found folder" << endl;
02952 lfFolder = dynamic_cast<KMFolder*>( node );
02953 }
02954 if ( !lfFolder || !lfFolder->createChildFolder() || !lfFolder->storage() )
02955 break;
02956
02957
02958 QDate today = QDate::currentDate();
02959 QString baseName = folder()->label() + "-" + QString::number( today.year() )
02960 + (today.month() < 10 ? "0" : "" ) + QString::number( today.month() )
02961 + (today.day() < 10 ? "0" : "" ) + QString::number( today.day() );
02962 QString name = baseName;
02963 int suffix = 0;
02964 while ( (node = lfFolder->child()->hasNamedFolder( name )) ) {
02965 ++suffix;
02966 name = baseName + '-' + QString::number( suffix );
02967 }
02968 kdDebug(5006) << k_funcinfo << "creating lost+found folder " << name << endl;
02969 dest = kmkernel->dimapFolderMgr()->createFolder( name, false, KMFolderTypeCachedImap, lfFolder->child() );
02970 if ( !dest || !dest->storage() )
02971 break;
02972 static_cast<KMFolderCachedImap*>( dest->storage() )->initializeFrom(
02973 static_cast<KMFolderCachedImap*>( lfFolder->storage() ) );
02974 dest->storage()->setContentsType( contentsType() );
02975 dest->storage()->writeConfig();
02976
02977 KMessageBox::sorry( 0, i18n("<p>There are new messages in folder <b>%1</b>, which "
02978 "have not been uploaded to the server yet, but the folder has been deleted "
02979 "on the server or you do not "
02980 "have sufficient access rights on the folder to upload them.</p>"
02981 "<p>All affected messages will therefore be moved to <b>%2</b> "
02982 "to avoid data loss.</p>").arg( folder()->prettyURL() ).arg( dest->prettyURL() ),
02983 i18n("Insufficient access rights") );
02984 manualMove = false;
02985 break;
02986 }
02987
02988 if ( manualMove ) {
02989 const QString msg ( i18n( "<p>There are new messages in this folder (%1), which "
02990 "have not been uploaded to the server yet, but the folder has been deleted "
02991 "on the server or you do not "
02992 "have sufficient access rights on the folder now to upload them. "
02993 "Please contact your administrator to allow upload of new messages "
02994 "to you, or move them out of this folder.</p> "
02995 "<p>Do you want to move these messages to another folder now?</p>").arg( folder()->prettyURL() ) );
02996 if ( KMessageBox::warningYesNo( 0, msg, QString::null, i18n("Move"), i18n("Do Not Move") ) == KMessageBox::Yes ) {
02997 KMail::KMFolderSelDlg dlg( kmkernel->getKMMainWidget(),
02998 i18n("Move Messages to Folder"), true );
02999 if ( dlg.exec() ) {
03000 dest = dlg.folder();
03001 }
03002 }
03003 }
03004 if ( dest ) {
03005 QPtrList<KMMsgBase> msgs;
03006 for( int i = 0; i < count(); ++i ) {
03007 KMMsgBase *msg = getMsgBase( i );
03008 if( !msg ) continue;
03009 if ( msg->UID() == 0 )
03010 msgs.append( msg );
03011 }
03012 KMCommand *command = new KMMoveCommand( dest, msgs );
03013 command->start();
03014 return command;
03015 }
03016 return 0;
03017 }
03018
03019 void KMFolderCachedImap::rescueUnsyncedMessagesAndDeleteFolder( KMFolder *folder, bool root )
03020 {
03021 kdDebug() << k_funcinfo << folder << " " << root << endl;
03022 if ( root )
03023 mToBeDeletedAfterRescue.append( folder );
03024 folder->open("cachedimap");
03025 KMFolderCachedImap* storage = dynamic_cast<KMFolderCachedImap*>( folder->storage() );
03026 if ( storage ) {
03027 KMCommand *command = storage->rescueUnsyncedMessages();
03028 if ( command ) {
03029 connect( command, SIGNAL(completed(KMCommand*)),
03030 SLOT(slotRescueDone(KMCommand*)) );
03031 ++mRescueCommandCount;
03032 } else {
03033
03034
03035 folder->close("cachedimap");
03036 }
03037 }
03038 if ( folder->child() ) {
03039 KMFolderNode *node = folder->child()->first();
03040 while (node) {
03041 if (!node->isDir() ) {
03042 KMFolder *subFolder = static_cast<KMFolder*>( node );
03043 rescueUnsyncedMessagesAndDeleteFolder( subFolder, false );
03044 }
03045 node = folder->child()->next();
03046 }
03047 }
03048 }
03049
03050 void KMFolderCachedImap::slotRescueDone(KMCommand * command)
03051 {
03052
03053 if ( command )
03054 --mRescueCommandCount;
03055 if ( mRescueCommandCount > 0 )
03056 return;
03057 for ( QValueList<KMFolder*>::ConstIterator it = mToBeDeletedAfterRescue.constBegin();
03058 it != mToBeDeletedAfterRescue.constEnd(); ++it ) {
03059 kmkernel->dimapFolderMgr()->remove( *it );
03060 }
03061 mToBeDeletedAfterRescue.clear();
03062 serverSyncInternal();
03063 }
03064
03065 bool KMFolderCachedImap::canDeleteMessages() const
03066 {
03067 if ( isReadOnly() )
03068 return false;
03069 if ( userRights() > 0 && !(userRights() & ACLJobs::Delete) )
03070 return false;
03071 return true;
03072 }
03073
03074 #include "kmfoldercachedimap.moc"