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