00001
00032 #ifdef HAVE_CONFIG_H
00033 #include <config.h>
00034 #endif
00035
00036 #include <errno.h>
00037
00038 #include "kmfoldercachedimap.h"
00039 #include "undostack.h"
00040 #include "kmfoldermgr.h"
00041 #include "kmacctcachedimap.h"
00042 #include "accountmanager.h"
00043 using KMail::AccountManager;
00044 #include "kmailicalifaceimpl.h"
00045 #include "kmfolder.h"
00046 #include "kmglobal.h"
00047 #include "acljobs.h"
00048 #include "broadcaststatus.h"
00049 using KPIM::BroadcastStatus;
00050 #include "progressmanager.h"
00051
00052 using KMail::CachedImapJob;
00053 #include "imapaccountbase.h"
00054 using KMail::ImapAccountBase;
00055 #include "listjob.h"
00056 using KMail::ListJob;
00057
00058 #include "kmfolderseldlg.h"
00059 #include "kmcommands.h"
00060
00061 #include <kapplication.h>
00062 #include <kmessagebox.h>
00063 #include <klocale.h>
00064 #include <kdebug.h>
00065 #include <kconfig.h>
00066 #include <kio/global.h>
00067 #include <kio/scheduler.h>
00068 #include <qbuffer.h>
00069 #include <qfile.h>
00070 #include <qlabel.h>
00071 #include <qlayout.h>
00072 #include <qvaluelist.h>
00073 #include "annotationjobs.h"
00074 #include "quotajobs.h"
00075 using namespace KMail;
00076 #include <globalsettings.h>
00077
00078 #define UIDCACHE_VERSION 1
00079 #define MAIL_LOSS_DEBUGGING 0
00080
00081 static QString incidencesForToString( KMFolderCachedImap::IncidencesFor r ) {
00082 switch (r) {
00083 case KMFolderCachedImap::IncForNobody: return "nobody";
00084 case KMFolderCachedImap::IncForAdmins: return "admins";
00085 case KMFolderCachedImap::IncForReaders: return "readers";
00086 }
00087 return QString::null;
00088 }
00089
00090 static KMFolderCachedImap::IncidencesFor incidencesForFromString( const QString& str ) {
00091 if ( str == "nobody" ) return KMFolderCachedImap::IncForNobody;
00092 if ( str == "admins" ) return KMFolderCachedImap::IncForAdmins;
00093 if ( str == "readers" ) return KMFolderCachedImap::IncForReaders;
00094 return KMFolderCachedImap::IncForAdmins;
00095 }
00096
00097 DImapTroubleShootDialog::DImapTroubleShootDialog( QWidget* parent,
00098 const char* name )
00099 : KDialogBase( Plain, i18n( "Troubleshooting IMAP Cache" ),
00100 Cancel | User1 | User2, Cancel, parent, name, true ),
00101 rc( Cancel )
00102 {
00103 QFrame* page = plainPage();
00104 QVBoxLayout *topLayout = new QVBoxLayout( page, 0 );
00105 QString txt = i18n( "<p><b>Troubleshooting the IMAP cache.</b></p>"
00106 "<p>If you have problems with synchronizing an IMAP "
00107 "folder, you should first try rebuilding the index "
00108 "file. This will take some time to rebuild, but will "
00109 "not cause any problems.</p><p>If that is not enough, "
00110 "you can try refreshing the IMAP cache. If you do this, "
00111 "you will loose all your local changes for this folder "
00112 "and all its subfolders.</p>" );
00113 topLayout->addWidget( new QLabel( txt, page ) );
00114 enableButtonSeparator( true );
00115
00116 setButtonText( User1, i18n( "Refresh &Cache" ) );
00117 setButtonText( User2, i18n( "Rebuild &Index" ) );
00118
00119 connect( this, SIGNAL( user1Clicked () ), this, SLOT( slotRebuildCache() ) );
00120 connect( this, SIGNAL( user2Clicked () ), this, SLOT( slotRebuildIndex() ) );
00121 }
00122
00123 int DImapTroubleShootDialog::run()
00124 {
00125 DImapTroubleShootDialog d;
00126 d.exec();
00127 return d.rc;
00128 }
00129
00130 void DImapTroubleShootDialog::slotRebuildCache()
00131 {
00132 rc = User1;
00133 done( User1 );
00134 }
00135
00136 void DImapTroubleShootDialog::slotRebuildIndex()
00137 {
00138 rc = User2;
00139 done( User2 );
00140 }
00141
00142
00143 KMFolderCachedImap::KMFolderCachedImap( KMFolder* folder, const char* aName )
00144 : KMFolderMaildir( folder, aName ),
00145 mSyncState( SYNC_STATE_INITIAL ), mContentState( imapNoInformation ),
00146 mSubfolderState( imapNoInformation ),
00147 mIncidencesFor( IncForAdmins ),
00148 mIsSelected( false ),
00149 mCheckFlags( true ), mReadOnly( false ), mAccount( NULL ), uidMapDirty( true ),
00150 uidWriteTimer( -1 ), mLastUid( 0 ), mTentativeHighestUid( 0 ),
00151 mFoundAnIMAPDigest( false ),
00152 mUserRights( 0 ), mSilentUpload( false ),
00153 mFolderRemoved( false ),
00154 mRecurse( true ),
00155 mStatusChangedLocally( false ), mAnnotationFolderTypeChanged( false ),
00156 mIncidencesForChanged( false ), mPersonalNamespacesCheckDone( true ),
00157 mQuotaInfo()
00158 {
00159 setUidValidity("");
00160
00161 if ( readUidCache() == -1 ) {
00162 if ( QFile::exists( uidCacheLocation() ) ) {
00163 KMessageBox::error( 0,
00164 i18n( "The UID cache file for folder %1 could not be read. There "
00165 "could be a problem with file system permission, or it is corrupted."
00166 ).arg( folder->prettyURL() ) );
00167
00168
00169 unlink( QFile::encodeName( uidCacheLocation() ) );
00170 }
00171 }
00172
00173 mProgress = 0;
00174 }
00175
00176 KMFolderCachedImap::~KMFolderCachedImap()
00177 {
00178 if( !mFolderRemoved ) {
00179 writeConfig();
00180 writeUidCache();
00181 }
00182
00183 if (kmkernel->undoStack()) kmkernel->undoStack()->folderDestroyed( folder() );
00184 }
00185
00186 void KMFolderCachedImap::initializeFrom( KMFolderCachedImap* parent )
00187 {
00188 setAccount( parent->account() );
00189
00190
00191 mAccount->removeDeletedFolder( imapPath() );
00192 setUserRights( parent->userRights() );
00193 }
00194
00195 void KMFolderCachedImap::readConfig()
00196 {
00197 KConfig* config = KMKernel::config();
00198 KConfigGroupSaver saver( config, "Folder-" + folder()->idString() );
00199 if( mImapPath.isEmpty() ) mImapPath = config->readEntry( "ImapPath" );
00200 if( QString( name() ).upper() == "INBOX" && mImapPath == "/INBOX/" )
00201 {
00202 folder()->setLabel( i18n( "inbox" ) );
00203
00204 folder()->setSystemFolder( true );
00205 }
00206 mNoContent = config->readBoolEntry( "NoContent", false );
00207 mReadOnly = config->readBoolEntry( "ReadOnly", false );
00208
00209 if ( mAnnotationFolderType != "FROMSERVER" ) {
00210 mAnnotationFolderType = config->readEntry( "Annotation-FolderType" );
00211
00212 if ( !mAnnotationFolderType.isEmpty() && !mAnnotationFolderType.startsWith( "mail" ) )
00213 kmkernel->iCalIface().setStorageFormat( folder(), KMailICalIfaceImpl::StorageXML );
00214
00215
00216 }
00217 mIncidencesFor = incidencesForFromString( config->readEntry( "IncidencesFor" ) );
00218
00219
00220
00221 mUserRights = config->readNumEntry( "UserRights", 0 );
00222
00223 int storageQuotaUsage = config->readNumEntry( "StorageQuotaUsage", -1 );
00224 int storageQuotaLimit = config->readNumEntry( "StorageQuotaLimit", -1 );
00225 QString storageQuotaRoot = config->readEntry( "StorageQuotaRoot", QString::null );
00226 if ( !storageQuotaRoot.isNull() ) {
00227 mQuotaInfo.setName( "STORAGE" );
00228 mQuotaInfo.setRoot( storageQuotaRoot );
00229
00230 if ( storageQuotaUsage > -1 )
00231 mQuotaInfo.setCurrent( storageQuotaUsage );
00232 if ( storageQuotaLimit > -1 )
00233 mQuotaInfo.setMax( storageQuotaLimit );
00234 }
00235
00236 KMFolderMaildir::readConfig();
00237
00238 mStatusChangedLocally =
00239 config->readBoolEntry( "StatusChangedLocally", false );
00240
00241 mAnnotationFolderTypeChanged = config->readBoolEntry( "AnnotationFolderTypeChanged", false );
00242 mIncidencesForChanged = config->readBoolEntry( "IncidencesForChanged", false );
00243 if ( mImapPath.isEmpty() ) {
00244 mImapPathCreation = config->readEntry("ImapPathCreation");
00245 }
00246 }
00247
00248 void KMFolderCachedImap::writeConfig()
00249 {
00250 KConfigGroup configGroup( KMKernel::config(), "Folder-" + folder()->idString() );
00251 configGroup.writeEntry( "ImapPath", mImapPath );
00252 configGroup.writeEntry( "NoContent", mNoContent );
00253 configGroup.writeEntry( "ReadOnly", mReadOnly );
00254 configGroup.writeEntry( "StatusChangedLocally", mStatusChangedLocally );
00255 if ( !mImapPathCreation.isEmpty() ) {
00256 if ( mImapPath.isEmpty() ) {
00257 configGroup.writeEntry( "ImapPathCreation", mImapPathCreation );
00258 } else {
00259 configGroup.deleteEntry( "ImapPathCreation" );
00260 }
00261 }
00262 writeConfigKeysWhichShouldNotGetOverwrittenByReadConfig();
00263 KMFolderMaildir::writeConfig();
00264 }
00265
00266 void KMFolderCachedImap::writeConfigKeysWhichShouldNotGetOverwrittenByReadConfig()
00267 {
00268 KConfigGroup configGroup( KMKernel::config(), "Folder-" + folder()->idString() );
00269 if ( !folder()->noContent() )
00270 {
00271 configGroup.writeEntry( "AnnotationFolderTypeChanged", mAnnotationFolderTypeChanged );
00272 configGroup.writeEntry( "Annotation-FolderType", mAnnotationFolderType );
00273 configGroup.writeEntry( "IncidencesForChanged", mIncidencesForChanged );
00274 configGroup.writeEntry( "IncidencesFor", incidencesForToString( mIncidencesFor ) );
00275 configGroup.writeEntry( "UserRights", mUserRights );
00276
00277 if ( mQuotaInfo.isValid() ) {
00278 if ( mQuotaInfo.current().isValid() ) {
00279 configGroup.writeEntry( "StorageQuotaUsage", mQuotaInfo.current().toInt() );
00280 }
00281 if ( mQuotaInfo.max().isValid() ) {
00282 configGroup.writeEntry( "StorageQuotaLimit", mQuotaInfo.max().toInt() );
00283 }
00284 configGroup.writeEntry( "StorageQuotaRoot", mQuotaInfo.root() );
00285 } else {
00286 configGroup.deleteEntry( "StorageQuotaUsage");
00287 configGroup.deleteEntry( "StorageQuotaRoot");
00288 configGroup.deleteEntry( "StorageQuotaLimit");
00289 }
00290 }
00291 }
00292
00293 int KMFolderCachedImap::create()
00294 {
00295 int rc = KMFolderMaildir::create();
00296
00297 readConfig();
00298 mUnreadMsgs = -1;
00299 return rc;
00300 }
00301
00302 void KMFolderCachedImap::remove()
00303 {
00304 mFolderRemoved = true;
00305
00306 QString part1 = folder()->path() + "/." + dotEscape(name());
00307 QString uidCacheFile = part1 + ".uidcache";
00308
00309
00310 if( QFile::exists(uidCacheFile) )
00311 unlink( QFile::encodeName( uidCacheFile ) );
00312
00313 FolderStorage::remove();
00314 }
00315
00316 QString KMFolderCachedImap::uidCacheLocation() const
00317 {
00318 QString sLocation(folder()->path());
00319 if (!sLocation.isEmpty()) sLocation += '/';
00320 return sLocation + '.' + dotEscape(fileName()) + ".uidcache";
00321 }
00322
00323 int KMFolderCachedImap::readUidCache()
00324 {
00325 QFile uidcache( uidCacheLocation() );
00326 if( uidcache.open( IO_ReadOnly ) ) {
00327 char buf[1024];
00328 int len = uidcache.readLine( buf, sizeof(buf) );
00329 if( len > 0 ) {
00330 int cacheVersion;
00331 sscanf( buf, "# KMail-UidCache V%d\n", &cacheVersion );
00332 if( cacheVersion == UIDCACHE_VERSION ) {
00333 len = uidcache.readLine( buf, sizeof(buf) );
00334 if( len > 0 ) {
00335 setUidValidity( QString::fromLocal8Bit( buf).stripWhiteSpace() );
00336 len = uidcache.readLine( buf, sizeof(buf) );
00337 if( len > 0 ) {
00338
00339 setLastUid( QString::fromLocal8Bit( buf).stripWhiteSpace().toULong() );
00340 return 0;
00341 }
00342 }
00343 }
00344 }
00345 }
00346 return -1;
00347 }
00348
00349 int KMFolderCachedImap::writeUidCache()
00350 {
00351 if( uidValidity().isEmpty() || uidValidity() == "INVALID" ) {
00352
00353 if( QFile::exists( uidCacheLocation() ) )
00354 return unlink( QFile::encodeName( uidCacheLocation() ) );
00355 return 0;
00356 }
00357
00358 QFile uidcache( uidCacheLocation() );
00359 if( uidcache.open( IO_WriteOnly ) ) {
00360 QTextStream str( &uidcache );
00361 str << "# KMail-UidCache V" << UIDCACHE_VERSION << endl;
00362 str << uidValidity() << endl;
00363 str << lastUid() << endl;
00364 uidcache.flush();
00365 if ( uidcache.status() == IO_Ok ) {
00366 fsync( uidcache.handle() );
00367 uidcache.close();
00368 if ( uidcache.status() == IO_Ok )
00369 return 0;
00370 }
00371 }
00372 KMessageBox::error( 0,
00373 i18n( "The UID cache file for folder %1 could not be written. There "
00374 "could be a problem with file system permission." ).arg( folder()->prettyURL() ) );
00375
00376 return -1;
00377 }
00378
00379 void KMFolderCachedImap::reloadUidMap()
00380 {
00381
00382 uidMap.clear();
00383 open();
00384 for( int i = 0; i < count(); ++i ) {
00385 KMMsgBase *msg = getMsgBase( i );
00386 if( !msg ) continue;
00387 ulong uid = msg->UID();
00388
00389 uidMap.insert( uid, i );
00390 }
00391 close();
00392 uidMapDirty = false;
00393 }
00394
00395
00396 KMMessage* KMFolderCachedImap::take(int idx)
00397 {
00398 uidMapDirty = true;
00399 return KMFolderMaildir::take(idx);
00400 }
00401
00402
00403 int KMFolderCachedImap::addMsgInternal( KMMessage* msg, bool newMail,
00404 int* index_return )
00405 {
00406
00407 ulong uid = msg->UID();
00408 if( uid != 0 ) {
00409 uidMapDirty = true;
00410 }
00411
00412
00413 int rc = KMFolderMaildir::addMsg(msg, index_return);
00414
00415 if( newMail && imapPath() == "/INBOX/" )
00416
00417 mAccount->processNewMsg( msg );
00418
00419 return rc;
00420 }
00421
00422
00423 int KMFolderCachedImap::addMsg(KMMessage* msg, int* index_return)
00424 {
00425 if ( !canAddMsgNow( msg, index_return ) ) return 0;
00426
00427 int rc = KMFolderMaildir::addMsgInternal(msg, index_return, true );
00428 return rc;
00429 }
00430
00431
00432
00433 void KMFolderCachedImap::removeMsg(int idx, bool imapQuiet)
00434 {
00435 uidMapDirty = true;
00436
00437 KMFolderMaildir::removeMsg(idx,imapQuiet);
00438 }
00439
00440 bool KMFolderCachedImap::canRemoveFolder() const {
00441
00442 if( folder() && folder()->child() && folder()->child()->count() > 0 )
00443 return false;
00444
00445 #if 0
00446
00447 return KMFolderMaildir::canRemoveFolder();
00448 #endif
00449 return true;
00450 }
00451
00452
00453 int KMFolderCachedImap::rename( const QString& aName,
00454 KMFolderDir* )
00455 {
00456 QString oldName = mAccount->renamedFolder( imapPath() );
00457 if ( oldName.isEmpty() ) oldName = name();
00458 if ( aName == oldName )
00459
00460 return 0;
00461
00462 if( account() == 0 || imapPath().isEmpty() ) {
00463 QString err = i18n("You must synchronize with the server before renaming IMAP folders.");
00464 KMessageBox::error( 0, err );
00465 return -1;
00466 }
00467
00468
00469
00470
00471
00472
00473 if ( name() != aName )
00474 mAccount->addRenamedFolder( imapPath(), folder()->label(), aName );
00475 else
00476 mAccount->removeRenamedFolder( imapPath() );
00477
00478 folder()->setLabel( aName );
00479 emit nameChanged();
00480
00481 return 0;
00482 }
00483
00484 KMFolder* KMFolderCachedImap::trashFolder() const
00485 {
00486 QString trashStr = account()->trash();
00487 return kmkernel->dimapFolderMgr()->findIdString( trashStr );
00488 }
00489
00490 void KMFolderCachedImap::setLastUid( ulong uid )
00491 {
00492 mLastUid = uid;
00493 if( uidWriteTimer == -1 )
00494
00495 uidWriteTimer = startTimer( 60000 );
00496 }
00497
00498 void KMFolderCachedImap::timerEvent( QTimerEvent* )
00499 {
00500 killTimer( uidWriteTimer );
00501 uidWriteTimer = -1;
00502 if ( writeUidCache() == -1 )
00503 unlink( QFile::encodeName( uidCacheLocation() ) );
00504 }
00505
00506 ulong KMFolderCachedImap::lastUid()
00507 {
00508 return mLastUid;
00509 }
00510
00511 KMMsgBase* KMFolderCachedImap::findByUID( ulong uid )
00512 {
00513 bool mapReloaded = false;
00514 if( uidMapDirty ) {
00515 reloadUidMap();
00516 mapReloaded = true;
00517 }
00518
00519 QMap<ulong,int>::Iterator it = uidMap.find( uid );
00520 if( it != uidMap.end() ) {
00521 KMMsgBase *msg = getMsgBase( *it );
00522 #if MAIL_LOSS_DEBUGGING
00523 kdDebug(5006) << "UID " << uid << " is supposed to be in the map" << endl;
00524 kdDebug(5006) << "UID's index is to be " << *it << endl;
00525 kdDebug(5006) << "There is a message there? " << (msg != 0) << endl;
00526 if ( msg ) {
00527 kdDebug(5006) << "Its UID is: " << msg->UID() << endl;
00528 }
00529 #endif
00530
00531 if( msg && msg->UID() == uid )
00532 return msg;
00533 kdDebug(5006) << "########## Didn't find uid: " << uid << "in cache athough it's supposed to be there!" << endl;
00534 } else {
00535 #if MAIL_LOSS_DEBUGGING
00536 kdDebug(5006) << "Didn't find uid: " << uid << "in cache!" << endl;
00537 #endif
00538 }
00539
00540
00541
00542 return 0;
00543
00544 reloadUidMap();
00545 it = uidMap.find( uid );
00546 if( it != uidMap.end() )
00547
00548 return getMsgBase( *it );
00549 #if MAIL_LOSS_DEBUGGING
00550 else
00551 kdDebug(5006) << "Reloaded, but stil didn't find uid: " << uid << endl;
00552 #endif
00553
00554 return 0;
00555 }
00556
00557
00558
00559 KMAcctCachedImap *KMFolderCachedImap::account() const
00560 {
00561 if( (KMAcctCachedImap *)mAccount == 0 ) {
00562
00563 mAccount = static_cast<KMAcctCachedImap *>( kmkernel->acctMgr()->findByName( name() ) );
00564 }
00565
00566 return mAccount;
00567 }
00568
00569 void KMFolderCachedImap::slotTroubleshoot()
00570 {
00571 const int rc = DImapTroubleShootDialog::run();
00572
00573 if( rc == KDialogBase::User1 ) {
00574
00575 if( !account() ) {
00576 KMessageBox::sorry( 0, i18n("No account setup for this folder.\n"
00577 "Please try running a sync before this.") );
00578 return;
00579 }
00580 QString str = i18n("Are you sure you want to refresh the IMAP cache of "
00581 "the folder %1 and all its subfolders?\nThis will "
00582 "remove all changes you have done locally to your "
00583 "folders.").arg( label() );
00584 QString s1 = i18n("Refresh IMAP Cache");
00585 QString s2 = i18n("&Refresh");
00586 if( KMessageBox::warningContinueCancel( 0, str, s1, s2 ) ==
00587 KMessageBox::Continue )
00588 account()->invalidateIMAPFolders( this );
00589 } else if( rc == KDialogBase::User2 ) {
00590
00591 createIndexFromContents();
00592 KMessageBox::information( 0, i18n( "The index of this folder has been "
00593 "recreated." ) );
00594 }
00595 }
00596
00597 void KMFolderCachedImap::serverSync( bool recurse )
00598 {
00599 if( mSyncState != SYNC_STATE_INITIAL ) {
00600 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 ) {
00601 mSyncState = SYNC_STATE_INITIAL;
00602 } else return;
00603 }
00604
00605 mRecurse = recurse;
00606 assert( account() );
00607
00608 ProgressItem *progressItem = mAccount->mailCheckProgressItem();
00609 if ( progressItem ) {
00610 progressItem->reset();
00611 progressItem->setTotalItems( 100 );
00612 }
00613 mProgress = 0;
00614
00615 #if 0
00616 if( mHoldSyncs ) {
00617
00618 account()->mailCheckProgressItem()->setProgress( 100 );
00619 mProgress = 100;
00620 newState( mProgress, i18n("Synchronization skipped"));
00621 mSyncState = SYNC_STATE_INITIAL;
00622 emit folderComplete( this, true );
00623 return;
00624 }
00625 #endif
00626 mTentativeHighestUid = 0;
00627
00628 serverSyncInternal();
00629 }
00630
00631 QString KMFolderCachedImap::state2String( int state ) const
00632 {
00633 switch( state ) {
00634 case SYNC_STATE_INITIAL: return "SYNC_STATE_INITIAL";
00635 case SYNC_STATE_GET_USERRIGHTS: return "SYNC_STATE_GET_USERRIGHTS";
00636 case SYNC_STATE_PUT_MESSAGES: return "SYNC_STATE_PUT_MESSAGES";
00637 case SYNC_STATE_UPLOAD_FLAGS: return "SYNC_STATE_UPLOAD_FLAGS";
00638 case SYNC_STATE_CREATE_SUBFOLDERS: return "SYNC_STATE_CREATE_SUBFOLDERS";
00639 case SYNC_STATE_LIST_SUBFOLDERS: return "SYNC_STATE_LIST_SUBFOLDERS";
00640 case SYNC_STATE_LIST_NAMESPACES: return "SYNC_STATE_LIST_NAMESPACES";
00641 case SYNC_STATE_LIST_SUBFOLDERS2: return "SYNC_STATE_LIST_SUBFOLDERS2";
00642 case SYNC_STATE_DELETE_SUBFOLDERS: return "SYNC_STATE_DELETE_SUBFOLDERS";
00643 case SYNC_STATE_LIST_MESSAGES: return "SYNC_STATE_LIST_MESSAGES";
00644 case SYNC_STATE_DELETE_MESSAGES: return "SYNC_STATE_DELETE_MESSAGES";
00645 case SYNC_STATE_GET_MESSAGES: return "SYNC_STATE_GET_MESSAGES";
00646 case SYNC_STATE_EXPUNGE_MESSAGES: return "SYNC_STATE_EXPUNGE_MESSAGES";
00647 case SYNC_STATE_HANDLE_INBOX: return "SYNC_STATE_HANDLE_INBOX";
00648 case SYNC_STATE_TEST_ANNOTATIONS: return "SYNC_STATE_TEST_ANNOTATIONS";
00649 case SYNC_STATE_GET_ANNOTATIONS: return "SYNC_STATE_GET_ANNOTATIONS";
00650 case SYNC_STATE_SET_ANNOTATIONS: return "SYNC_STATE_SET_ANNOTATIONS";
00651 case SYNC_STATE_GET_ACLS: return "SYNC_STATE_GET_ACLS";
00652 case SYNC_STATE_SET_ACLS: return "SYNC_STATE_SET_ACLS";
00653 case SYNC_STATE_GET_QUOTA: return "SYNC_STATE_GET_QUOTA";
00654 case SYNC_STATE_FIND_SUBFOLDERS: return "SYNC_STATE_FIND_SUBFOLDERS";
00655 case SYNC_STATE_SYNC_SUBFOLDERS: return "SYNC_STATE_SYNC_SUBFOLDERS";
00656 case SYNC_STATE_RENAME_FOLDER: return "SYNC_STATE_RENAME_FOLDER";
00657 case SYNC_STATE_CHECK_UIDVALIDITY: return "SYNC_STATE_CHECK_UIDVALIDITY";
00658 default: return "Unknown state";
00659 }
00660 }
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693 void KMFolderCachedImap::serverSyncInternal()
00694 {
00695
00696
00697
00698 if( kmkernel->mailCheckAborted() ) {
00699 resetSyncState();
00700 emit folderComplete( this, false );
00701 return;
00702 }
00703
00704
00705 switch( mSyncState ) {
00706 case SYNC_STATE_INITIAL:
00707 {
00708 mProgress = 0;
00709 foldersForDeletionOnServer.clear();
00710 newState( mProgress, i18n("Synchronizing"));
00711
00712 open();
00713 if ( !noContent() )
00714 mAccount->addLastUnreadMsgCount( this, countUnread() );
00715
00716
00717 ImapAccountBase::ConnectionState cs = mAccount->makeConnection();
00718 if ( cs == ImapAccountBase::Error ) {
00719
00720
00721
00722 newState( mProgress, i18n( "Error connecting to server %1" ).arg( mAccount->host() ) );
00723 close();
00724 emit folderComplete(this, false);
00725 break;
00726 } else if ( cs == ImapAccountBase::Connecting ) {
00727 mAccount->setAnnotationCheckPassed( false );
00728
00729 newState( mProgress, i18n("Connecting to %1").arg( mAccount->host() ) );
00730
00731 connect( mAccount, SIGNAL( connectionResult(int, const QString&) ),
00732 this, SLOT( slotConnectionResult(int, const QString&) ) );
00733 break;
00734 } else {
00735
00736
00737 mSyncState = SYNC_STATE_GET_USERRIGHTS;
00738
00739 }
00740 }
00741
00742
00743 case SYNC_STATE_GET_USERRIGHTS:
00744
00745
00746 mSyncState = SYNC_STATE_RENAME_FOLDER;
00747
00748 if( !noContent() && mAccount->hasACLSupport() ) {
00749
00750 newState( mProgress, i18n("Checking permissions"));
00751 connect( mAccount, SIGNAL( receivedUserRights( KMFolder* ) ),
00752 this, SLOT( slotReceivedUserRights( KMFolder* ) ) );
00753 mAccount->getUserRights( folder(), imapPath() );
00754 break;
00755 }
00756
00757 case SYNC_STATE_RENAME_FOLDER:
00758 {
00759 mSyncState = SYNC_STATE_CHECK_UIDVALIDITY;
00760
00761 bool isResourceFolder = kmkernel->iCalIface().isStandardResourceFolder( folder() );
00762 QString newName = mAccount->renamedFolder( imapPath() );
00763 if ( !newName.isEmpty() && !folder()->isSystemFolder() && !isResourceFolder ) {
00764 newState( mProgress, i18n("Renaming folder") );
00765 CachedImapJob *job = new CachedImapJob( newName, CachedImapJob::tRenameFolder, this );
00766 connect( job, SIGNAL( result(KMail::FolderJob *) ), this, SLOT( slotIncreaseProgress() ) );
00767 connect( job, SIGNAL( finished() ), this, SLOT( serverSyncInternal() ) );
00768 job->start();
00769 break;
00770 }
00771 }
00772
00773 case SYNC_STATE_CHECK_UIDVALIDITY:
00774 mSyncState = SYNC_STATE_CREATE_SUBFOLDERS;
00775 if( !noContent() ) {
00776 checkUidValidity();
00777 break;
00778 }
00779
00780
00781 case SYNC_STATE_CREATE_SUBFOLDERS:
00782 mSyncState = SYNC_STATE_PUT_MESSAGES;
00783 createNewFolders();
00784 break;
00785
00786 case SYNC_STATE_PUT_MESSAGES:
00787 mSyncState = SYNC_STATE_UPLOAD_FLAGS;
00788 if( !noContent() ) {
00789 uploadNewMessages();
00790 break;
00791 }
00792
00793 case SYNC_STATE_UPLOAD_FLAGS:
00794 mSyncState = SYNC_STATE_LIST_NAMESPACES;
00795 if( !noContent() ) {
00796
00797 if( uidMapDirty )
00798 reloadUidMap();
00799
00800
00801 if ( mUserRights <= 0 || ( mUserRights & KMail::ACLJobs::WriteFlags ) ) {
00802 if ( mStatusChangedLocally ) {
00803 uploadFlags();
00804 break;
00805 } else {
00806
00807 }
00808 }
00809 }
00810
00811
00812 case SYNC_STATE_LIST_NAMESPACES:
00813 if ( this == mAccount->rootFolder() ) {
00814 listNamespaces();
00815 break;
00816 }
00817 mSyncState = SYNC_STATE_LIST_SUBFOLDERS;
00818
00819
00820 case SYNC_STATE_LIST_SUBFOLDERS:
00821 newState( mProgress, i18n("Retrieving folderlist"));
00822 mSyncState = SYNC_STATE_LIST_SUBFOLDERS2;
00823 if( !listDirectory() ) {
00824 mSyncState = SYNC_STATE_INITIAL;
00825 KMessageBox::error(0, i18n("Error while retrieving the folderlist"));
00826 }
00827 break;
00828
00829 case SYNC_STATE_LIST_SUBFOLDERS2:
00830 mSyncState = SYNC_STATE_DELETE_SUBFOLDERS;
00831 mProgress += 10;
00832 newState( mProgress, i18n("Retrieving subfolders"));
00833 listDirectory2();
00834 break;
00835
00836 case SYNC_STATE_DELETE_SUBFOLDERS:
00837 mSyncState = SYNC_STATE_LIST_MESSAGES;
00838 if( !foldersForDeletionOnServer.isEmpty() ) {
00839 newState( mProgress, i18n("Deleting folders from server"));
00840 CachedImapJob* job = new CachedImapJob( foldersForDeletionOnServer,
00841 CachedImapJob::tDeleteFolders, this );
00842 connect( job, SIGNAL( result(KMail::FolderJob *) ), this, SLOT( slotIncreaseProgress() ) );
00843 connect( job, SIGNAL( finished() ), this, SLOT( slotFolderDeletionOnServerFinished() ) );
00844 job->start();
00845 break;
00846 }
00847
00848
00849
00850
00851 case SYNC_STATE_LIST_MESSAGES:
00852 mSyncState = SYNC_STATE_DELETE_MESSAGES;
00853 if( !noContent() ) {
00854 newState( mProgress, i18n("Retrieving message list"));
00855 listMessages();
00856 break;
00857 }
00858
00859
00860 case SYNC_STATE_DELETE_MESSAGES:
00861 mSyncState = SYNC_STATE_EXPUNGE_MESSAGES;
00862 if( !noContent() ) {
00863 if( deleteMessages() ) {
00864
00865 } else {
00866
00867 newState( mProgress, i18n("No messages to delete..."));
00868 mSyncState = SYNC_STATE_GET_MESSAGES;
00869 serverSyncInternal();
00870 }
00871 break;
00872 }
00873
00874
00875 case SYNC_STATE_EXPUNGE_MESSAGES:
00876 mSyncState = SYNC_STATE_GET_MESSAGES;
00877 if( !noContent() ) {
00878 newState( mProgress, i18n("Expunging deleted messages"));
00879 CachedImapJob *job = new CachedImapJob( QString::null,
00880 CachedImapJob::tExpungeFolder, this );
00881 connect( job, SIGNAL( result(KMail::FolderJob *) ), this, SLOT( slotIncreaseProgress() ) );
00882 connect( job, SIGNAL( finished() ), this, SLOT( serverSyncInternal() ) );
00883 job->start();
00884 break;
00885 }
00886
00887
00888 case SYNC_STATE_GET_MESSAGES:
00889 mSyncState = SYNC_STATE_HANDLE_INBOX;
00890 if( !noContent() ) {
00891 if( !mMsgsForDownload.isEmpty() ) {
00892 newState( mProgress, i18n("Retrieving new messages"));
00893 CachedImapJob *job = new CachedImapJob( mMsgsForDownload,
00894 CachedImapJob::tGetMessage,
00895 this );
00896 connect( job, SIGNAL( progress(unsigned long, unsigned long) ),
00897 this, SLOT( slotProgress(unsigned long, unsigned long) ) );
00898 connect( job, SIGNAL( finished() ), this, SLOT( slotUpdateLastUid() ) );
00899 connect( job, SIGNAL( finished() ), this, SLOT( serverSyncInternal() ) );
00900 job->start();
00901 mMsgsForDownload.clear();
00902 break;
00903 } else {
00904 newState( mProgress, i18n("No new messages from server"));
00905
00906
00907
00908
00909
00910 slotUpdateLastUid();
00911 if( mLastUid == 0 && uidWriteTimer == -1 ) {
00912
00913 if ( writeUidCache() == -1 ) {
00914 resetSyncState();
00915 emit folderComplete( this, false );
00916 return;
00917 }
00918 }
00919 }
00920 }
00921
00922
00923
00924 case SYNC_STATE_HANDLE_INBOX:
00925
00926 mProgress = 95;
00927 mSyncState = SYNC_STATE_TEST_ANNOTATIONS;
00928
00929 #define KOLAB_FOLDERTEST "/vendor/kolab/folder-test"
00930 case SYNC_STATE_TEST_ANNOTATIONS:
00931 mSyncState = SYNC_STATE_GET_ANNOTATIONS;
00932
00933 if( !mAccount->annotationCheckPassed() &&
00934 ( mUserRights <= 0 || ( mUserRights & ACLJobs::Administer ) )
00935 && !imapPath().isEmpty() && imapPath() != "/" ) {
00936 kdDebug(5006) << "Setting test attribute on folder: "<< folder()->prettyURL() << endl;
00937 newState( mProgress, i18n("Checking annotation support"));
00938
00939 KURL url = mAccount->getUrl();
00940 url.setPath( imapPath() );
00941 KMail::AnnotationList annotations;
00942
00943 KMail::AnnotationAttribute attr( KOLAB_FOLDERTEST, "value.shared", "true" );
00944 annotations.append( attr );
00945
00946 kdDebug(5006) << "Setting test attribute to "<< url << endl;
00947 KIO::Job* job = AnnotationJobs::multiSetAnnotation( mAccount->slave(),
00948 url, annotations );
00949 ImapAccountBase::jobData jd( url.url(), folder() );
00950 jd.cancellable = true;
00951 mAccount->insertJob(job, jd);
00952 connect(job, SIGNAL(result(KIO::Job *)),
00953 SLOT(slotTestAnnotationResult(KIO::Job *)));
00954 break;
00955 }
00956
00957 case SYNC_STATE_GET_ANNOTATIONS: {
00958 #define KOLAB_FOLDERTYPE "/vendor/kolab/folder-type"
00959 #define KOLAB_INCIDENCESFOR "/vendor/kolab/incidences-for"
00960
00961 mSyncState = SYNC_STATE_SET_ANNOTATIONS;
00962
00963 bool needToGetInitialAnnotations = false;
00964 if ( !noContent() ) {
00965
00966 if ( mAnnotationFolderType == "FROMSERVER" ) {
00967 needToGetInitialAnnotations = true;
00968 mAnnotationFolderType = QString::null;
00969 } else {
00970 updateAnnotationFolderType();
00971 }
00972 }
00973
00974
00975
00976 if ( !noContent() && mAccount->hasAnnotationSupport() &&
00977 ( kmkernel->iCalIface().isEnabled() || needToGetInitialAnnotations ) ) {
00978 QStringList annotations;
00979 if ( !mAnnotationFolderTypeChanged || mAnnotationFolderType.isEmpty() )
00980 annotations << KOLAB_FOLDERTYPE;
00981 if ( !mIncidencesForChanged )
00982 annotations << KOLAB_INCIDENCESFOR;
00983 if ( !annotations.isEmpty() ) {
00984 newState( mProgress, i18n("Retrieving annotations"));
00985 KURL url = mAccount->getUrl();
00986 url.setPath( imapPath() );
00987 AnnotationJobs::MultiGetAnnotationJob* job =
00988 AnnotationJobs::multiGetAnnotation( mAccount->slave(), url, annotations );
00989 ImapAccountBase::jobData jd( url.url(), folder() );
00990 jd.cancellable = true;
00991 mAccount->insertJob(job, jd);
00992
00993 connect( job, SIGNAL(annotationResult(const QString&, const QString&, bool)),
00994 SLOT(slotAnnotationResult(const QString&, const QString&, bool)) );
00995 connect( job, SIGNAL(result(KIO::Job *)),
00996 SLOT(slotGetAnnotationResult(KIO::Job *)) );
00997 break;
00998 }
00999 }
01000 }
01001 case SYNC_STATE_SET_ANNOTATIONS:
01002
01003 mSyncState = SYNC_STATE_SET_ACLS;
01004 if ( !noContent() && mAccount->hasAnnotationSupport() &&
01005 ( mUserRights <= 0 || ( mUserRights & ACLJobs::Administer ) ) ) {
01006 newState( mProgress, i18n("Setting annotations"));
01007 KURL url = mAccount->getUrl();
01008 url.setPath( imapPath() );
01009 KMail::AnnotationList annotations;
01010 if ( mAnnotationFolderTypeChanged && !mAnnotationFolderType.isEmpty() ) {
01011 KMail::AnnotationAttribute attr( KOLAB_FOLDERTYPE, "value.shared", mAnnotationFolderType );
01012 annotations.append( attr );
01013 kdDebug(5006) << "Setting folder-type annotation for " << label() << " to " << mAnnotationFolderType << endl;
01014 }
01015 if ( mIncidencesForChanged ) {
01016 const QString val = incidencesForToString( mIncidencesFor );
01017 KMail::AnnotationAttribute attr( KOLAB_INCIDENCESFOR, "value.shared", val );
01018 annotations.append( attr );
01019 kdDebug(5006) << "Setting incidences-for annotation for " << label() << " to " << val << endl;
01020 }
01021 if ( !annotations.isEmpty() ) {
01022 KIO::Job* job =
01023 AnnotationJobs::multiSetAnnotation( mAccount->slave(), url, annotations );
01024 ImapAccountBase::jobData jd( url.url(), folder() );
01025 jd.cancellable = true;
01026 mAccount->insertJob(job, jd);
01027
01028 connect(job, SIGNAL(annotationChanged( const QString&, const QString&, const QString& ) ),
01029 SLOT( slotAnnotationChanged( const QString&, const QString&, const QString& ) ));
01030 connect(job, SIGNAL(result(KIO::Job *)),
01031 SLOT(slotSetAnnotationResult(KIO::Job *)));
01032 break;
01033 }
01034 }
01035
01036 case SYNC_STATE_SET_ACLS:
01037 mSyncState = SYNC_STATE_GET_ACLS;
01038
01039 if( !noContent() && mAccount->hasACLSupport() &&
01040 ( mUserRights <= 0 || ( mUserRights & ACLJobs::Administer ) ) ) {
01041 bool hasChangedACLs = false;
01042 ACLList::ConstIterator it = mACLList.begin();
01043 for ( ; it != mACLList.end() && !hasChangedACLs; ++it ) {
01044 hasChangedACLs = (*it).changed;
01045 }
01046 if ( hasChangedACLs ) {
01047 newState( mProgress, i18n("Setting permissions"));
01048 KURL url = mAccount->getUrl();
01049 url.setPath( imapPath() );
01050 KIO::Job* job = KMail::ACLJobs::multiSetACL( mAccount->slave(), url, mACLList );
01051 ImapAccountBase::jobData jd( url.url(), folder() );
01052 mAccount->insertJob(job, jd);
01053
01054 connect(job, SIGNAL(result(KIO::Job *)),
01055 SLOT(slotMultiSetACLResult(KIO::Job *)));
01056 connect(job, SIGNAL(aclChanged( const QString&, int )),
01057 SLOT(slotACLChanged( const QString&, int )) );
01058 break;
01059 }
01060 }
01061
01062 case SYNC_STATE_GET_ACLS:
01063 mSyncState = SYNC_STATE_GET_QUOTA;
01064
01065 if( !noContent() && mAccount->hasACLSupport() ) {
01066 newState( mProgress, i18n( "Retrieving permissions" ) );
01067 mAccount->getACL( folder(), mImapPath );
01068 connect( mAccount, SIGNAL(receivedACL( KMFolder*, KIO::Job*, const KMail::ACLList& )),
01069 this, SLOT(slotReceivedACL( KMFolder*, KIO::Job*, const KMail::ACLList& )) );
01070 break;
01071 }
01072 case SYNC_STATE_GET_QUOTA:
01073
01074 mSyncState = SYNC_STATE_FIND_SUBFOLDERS;
01075 if( !noContent() && mAccount->hasQuotaSupport() ) {
01076 newState( mProgress, i18n("Getting quota information"));
01077 KURL url = mAccount->getUrl();
01078 url.setPath( imapPath() );
01079 KIO::Job* job = KMail::QuotaJobs::getStorageQuota( mAccount->slave(), url );
01080 ImapAccountBase::jobData jd( url.url(), folder() );
01081 mAccount->insertJob(job, jd);
01082 connect( job, SIGNAL( storageQuotaResult( const QuotaInfo& ) ),
01083 SLOT( slotStorageQuotaResult( const QuotaInfo& ) ) );
01084 connect( job, SIGNAL(result(KIO::Job *)),
01085 SLOT(slotQuotaResult(KIO::Job *)) );
01086 break;
01087 }
01088 case SYNC_STATE_FIND_SUBFOLDERS:
01089 {
01090 mProgress = 98;
01091 newState( mProgress, i18n("Updating cache file"));
01092
01093 mSyncState = SYNC_STATE_SYNC_SUBFOLDERS;
01094 mSubfoldersForSync.clear();
01095 mCurrentSubfolder = 0;
01096 if( folder() && folder()->child() ) {
01097 KMFolderNode *node = folder()->child()->first();
01098 while( node ) {
01099 if( !node->isDir() ) {
01100 KMFolderCachedImap* storage = static_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage());
01101
01102 if ( !storage->imapPath().isEmpty()
01103
01104 && !foldersForDeletionOnServer.contains( storage->imapPath() ) ) {
01105 mSubfoldersForSync << storage;
01106 } else {
01107 kdDebug(5006) << "Do not add " << storage->label()
01108 << " to synclist" << endl;
01109 }
01110 }
01111 node = folder()->child()->next();
01112 }
01113 }
01114
01115
01116 mProgress = 100;
01117 newState( mProgress, i18n("Synchronization done"));
01118 KURL url = mAccount->getUrl();
01119 url.setPath( imapPath() );
01120 kmkernel->iCalIface().folderSynced( folder(), url );
01121 }
01122
01123 if ( !mRecurse )
01124 mSubfoldersForSync.clear();
01125
01126
01127 case SYNC_STATE_SYNC_SUBFOLDERS:
01128 {
01129 if( mCurrentSubfolder ) {
01130 disconnect( mCurrentSubfolder, SIGNAL( folderComplete(KMFolderCachedImap*, bool) ),
01131 this, SLOT( slotSubFolderComplete(KMFolderCachedImap*, bool) ) );
01132 mCurrentSubfolder = 0;
01133 }
01134
01135 if( mSubfoldersForSync.isEmpty() ) {
01136 mSyncState = SYNC_STATE_INITIAL;
01137 mAccount->addUnreadMsgCount( this, countUnread() );
01138 close();
01139 emit folderComplete( this, true );
01140 } else {
01141 mCurrentSubfolder = mSubfoldersForSync.front();
01142 mSubfoldersForSync.pop_front();
01143 connect( mCurrentSubfolder, SIGNAL( folderComplete(KMFolderCachedImap*, bool) ),
01144 this, SLOT( slotSubFolderComplete(KMFolderCachedImap*, bool) ) );
01145
01146
01147 assert( !mCurrentSubfolder->imapPath().isEmpty() );
01148 mCurrentSubfolder->setAccount( account() );
01149 bool recurse = mCurrentSubfolder->noChildren() ? false : true;
01150 mCurrentSubfolder->serverSync( recurse );
01151 }
01152 }
01153 break;
01154
01155 default:
01156 kdDebug(5006) << "KMFolderCachedImap::serverSyncInternal() WARNING: no such state "
01157 << mSyncState << endl;
01158 }
01159 }
01160
01161
01162
01163
01164 void KMFolderCachedImap::slotConnectionResult( int errorCode, const QString& errorMsg )
01165 {
01166 disconnect( mAccount, SIGNAL( connectionResult(int, const QString&) ),
01167 this, SLOT( slotConnectionResult(int, const QString&) ) );
01168 if ( !errorCode ) {
01169
01170 mSyncState = SYNC_STATE_GET_USERRIGHTS;
01171 mProgress += 5;
01172 serverSyncInternal();
01173 } else {
01174
01175 newState( mProgress, KIO::buildErrorString( errorCode, errorMsg ));
01176 emit folderComplete(this, FALSE);
01177 }
01178 }
01179
01180
01181 QValueList<unsigned long> KMFolderCachedImap::findNewMessages()
01182 {
01183 QValueList<unsigned long> result;
01184 for( int i = 0; i < count(); ++i ) {
01185 KMMsgBase *msg = getMsgBase( i );
01186 if( !msg ) continue;
01187 if ( msg->UID() == 0 )
01188 result.append( msg->getMsgSerNum() );
01189 }
01190 return result;
01191 }
01192
01193
01194 void KMFolderCachedImap::uploadNewMessages()
01195 {
01196 QValueList<unsigned long> newMsgs = findNewMessages();
01197 if( !newMsgs.isEmpty() ) {
01198 if ( mUserRights <= 0 || ( mUserRights & ( KMail::ACLJobs::Insert ) ) ) {
01199 newState( mProgress, i18n("Uploading messages to server"));
01200 CachedImapJob *job = new CachedImapJob( newMsgs, CachedImapJob::tPutMessage, this );
01201 connect( job, SIGNAL( progress( unsigned long, unsigned long) ),
01202 this, SLOT( slotPutProgress(unsigned long, unsigned long) ) );
01203 connect( job, SIGNAL( finished() ), this, SLOT( serverSyncInternal() ) );
01204 job->start();
01205 return;
01206 } else {
01207 const QString msg ( i18n( "<p>There are new messages in this folder (%1), which "
01208 "have not been uploaded to the server yet, but you do not seem to "
01209 "have sufficient access rights on the folder now to upload them. "
01210 "Please contact your administrator to allow upload of new messages "
01211 "to you, or move them out of this folder.</p> "
01212 "<p>Do you want to move these messages to another folder now?</p>").arg( folder()->prettyURL() ) );
01213 if ( KMessageBox::warningYesNo( 0, msg, QString::null, i18n("Move"), i18n("Do Not Move") ) == KMessageBox::Yes ) {
01214 KMail::KMFolderSelDlg dlg( kmkernel->getKMMainWidget(),
01215 i18n("Move Messages to Folder"), true );
01216 if ( dlg.exec() ) {
01217 KMFolder* dest = dlg.folder();
01218 if ( dest ) {
01219 QPtrList<KMMsgBase> msgs;
01220 for( int i = 0; i < count(); ++i ) {
01221 KMMsgBase *msg = getMsgBase( i );
01222 if( !msg ) continue;
01223 if ( msg->UID() == 0 )
01224 msgs.append( msg );
01225 }
01226 KMCommand *command = new KMMoveCommand( dest, msgs );
01227 connect( command, SIGNAL( completed( KMCommand * ) ),
01228 this, SLOT( serverSyncInternal() ) );
01229 command->start();
01230 return;
01231 }
01232 }
01233 }
01234 }
01235 }
01236 newState( mProgress, i18n("No messages to upload to server"));
01237 serverSyncInternal();
01238 }
01239
01240
01241 void KMFolderCachedImap::slotPutProgress( unsigned long done, unsigned long total )
01242 {
01243
01244 int progressSpan = 10;
01245 newState( mProgress + (progressSpan * done) / total, QString::null );
01246 if ( done == total )
01247 mProgress += progressSpan;
01248 }
01249
01250
01251 void KMFolderCachedImap::uploadFlags()
01252 {
01253 if ( !uidMap.isEmpty() ) {
01254 mStatusFlagsJobs = 0;
01255 newState( mProgress, i18n("Uploading status of messages to server"));
01256
01257
01258 QMap< QString, QStringList > groups;
01259
01260 for( int i = 0; i < count(); ++i ) {
01261 KMMsgBase* msg = getMsgBase( i );
01262 if( !msg || msg->UID() == 0 )
01263
01264 continue;
01265
01266 QString flags = KMFolderImap::statusToFlags(msg->status());
01267
01268 QString uid;
01269 uid.setNum( msg->UID() );
01270 groups[flags].append(uid);
01271 }
01272 QMapIterator< QString, QStringList > dit;
01273 for( dit = groups.begin(); dit != groups.end(); ++dit ) {
01274 QCString flags = dit.key().latin1();
01275 QStringList sets = KMFolderImap::makeSets( (*dit), true );
01276 mStatusFlagsJobs += sets.count();
01277
01278 for( QStringList::Iterator slit = sets.begin(); slit != sets.end(); ++slit ) {
01279 QString imappath = imapPath() + ";UID=" + ( *slit );
01280 mAccount->setImapStatus(folder(), imappath, flags);
01281 }
01282 }
01283
01284
01285 if ( mStatusFlagsJobs ) {
01286 connect( mAccount, SIGNAL( imapStatusChanged(KMFolder*, const QString&, bool) ),
01287 this, SLOT( slotImapStatusChanged(KMFolder*, const QString&, bool) ) );
01288 return;
01289 }
01290 }
01291 newState( mProgress, i18n("No messages to upload to server"));
01292 serverSyncInternal();
01293 }
01294
01295 void KMFolderCachedImap::slotImapStatusChanged(KMFolder* folder, const QString&, bool cont)
01296 {
01297 if ( mSyncState == SYNC_STATE_INITIAL ){
01298
01299 return;
01300 }
01301
01302 if ( folder->storage() == this ) {
01303 --mStatusFlagsJobs;
01304 if ( mStatusFlagsJobs == 0 || !cont )
01305 disconnect( mAccount, SIGNAL( imapStatusChanged(KMFolder*, const QString&, bool) ),
01306 this, SLOT( slotImapStatusChanged(KMFolder*, const QString&, bool) ) );
01307 if ( mStatusFlagsJobs == 0 && cont ) {
01308 mProgress += 5;
01309 serverSyncInternal();
01310
01311 }
01312 }
01313 }
01314
01315
01316 void KMFolderCachedImap::setStatus( int idx, KMMsgStatus status, bool toggle)
01317 {
01318 KMFolderMaildir::setStatus( idx, status, toggle );
01319 mStatusChangedLocally = true;
01320 }
01321
01322 void KMFolderCachedImap::setStatus(QValueList<int>& ids, KMMsgStatus status, bool toggle)
01323 {
01324 KMFolderMaildir::setStatus(ids, status, toggle);
01325 mStatusChangedLocally = true;
01326 }
01327
01328
01329 void KMFolderCachedImap::createNewFolders()
01330 {
01331 QValueList<KMFolderCachedImap*> newFolders = findNewFolders();
01332
01333 if( !newFolders.isEmpty() ) {
01334 newState( mProgress, i18n("Creating subfolders on server"));
01335 CachedImapJob *job = new CachedImapJob( newFolders, CachedImapJob::tAddSubfolders, this );
01336 connect( job, SIGNAL( result(KMail::FolderJob *) ), this, SLOT( slotIncreaseProgress() ) );
01337 connect( job, SIGNAL( finished() ), this, SLOT( serverSyncInternal() ) );
01338 job->start();
01339 } else {
01340 serverSyncInternal();
01341 }
01342 }
01343
01344 QValueList<KMFolderCachedImap*> KMFolderCachedImap::findNewFolders()
01345 {
01346 QValueList<KMFolderCachedImap*> newFolders;
01347 if( folder() && folder()->child() ) {
01348 KMFolderNode *node = folder()->child()->first();
01349 while( node ) {
01350 if( !node->isDir() ) {
01351 if( static_cast<KMFolder*>(node)->folderType() != KMFolderTypeCachedImap ) {
01352 kdError(5006) << "KMFolderCachedImap::findNewFolders(): ARGH!!! "
01353 << node->name() << " is not an IMAP folder\n";
01354 node = folder()->child()->next();
01355 assert(0);
01356 }
01357 KMFolderCachedImap* folder = static_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage());
01358 if( folder->imapPath().isEmpty() ) {
01359 newFolders << folder;
01360 }
01361 }
01362 node = folder()->child()->next();
01363 }
01364 }
01365 return newFolders;
01366 }
01367
01368 bool KMFolderCachedImap::deleteMessages()
01369 {
01370 if ( mUserRights > 0 && !( mUserRights & KMail::ACLJobs::Delete ) )
01371 return false;
01372
01373 QPtrList<KMMessage> msgsForDeletion;
01374
01375
01376
01377
01378
01379 QStringList uids;
01380 QMap<ulong,int>::const_iterator it = uidMap.constBegin();
01381 for( ; it != uidMap.end(); it++ ) {
01382 ulong uid ( it.key() );
01383 if( uid!=0 && !uidsOnServer.find( uid ) ) {
01384 uids << QString::number( uid );
01385 msgsForDeletion.append( getMsg( *it ) );
01386 }
01387 }
01388
01389 if( !msgsForDeletion.isEmpty() ) {
01390 #if MAIL_LOSS_DEBUGGING
01391 if ( KMessageBox::warningYesNo(
01392 0, i18n( "<qt><p>Mails on the server in folder <b>%1</b> were deleted. "
01393 "Do you want to delete them locally?<br>UIDs: %2</p></qt>" )
01394 .arg( folder()->prettyURL() ).arg( uids.join(",") ) ) == KMessageBox::Yes )
01395 #endif
01396 removeMsg( msgsForDeletion );
01397 }
01398
01399
01400 if( !uidsForDeletionOnServer.isEmpty() ) {
01401 newState( mProgress, i18n("Deleting removed messages from server"));
01402 QStringList sets = KMFolderImap::makeSets( uidsForDeletionOnServer, true );
01403 uidsForDeletionOnServer.clear();
01404 kdDebug(5006) << "Deleting " << sets.count() << " sets of messages from server folder " << imapPath() << endl;
01405 CachedImapJob *job = new CachedImapJob( sets, CachedImapJob::tDeleteMessage, this );
01406 connect( job, SIGNAL( result(KMail::FolderJob *) ),
01407 this, SLOT( slotDeleteMessagesResult(KMail::FolderJob *) ) );
01408 job->start();
01409 return true;
01410 } else {
01411 return false;
01412 }
01413 }
01414
01415 void KMFolderCachedImap::slotDeleteMessagesResult( KMail::FolderJob* job )
01416 {
01417 if ( job->error() ) {
01418
01419 mSyncState = SYNC_STATE_GET_MESSAGES;
01420 }
01421 mProgress += 10;
01422 serverSyncInternal();
01423 }
01424
01425 void KMFolderCachedImap::checkUidValidity() {
01426
01427
01428 if( imapPath().isEmpty() || imapPath() == "/" )
01429
01430 serverSyncInternal();
01431 else {
01432 newState( mProgress, i18n("Checking folder validity"));
01433 CachedImapJob *job = new CachedImapJob( FolderJob::tCheckUidValidity, this );
01434 connect( job, SIGNAL( result( KMail::FolderJob* ) ),
01435 this, SLOT( slotCheckUidValidityResult( KMail::FolderJob* ) ) );
01436 job->start();
01437 }
01438 }
01439
01440 void KMFolderCachedImap::slotCheckUidValidityResult( KMail::FolderJob* job )
01441 {
01442 if ( job->error() ) {
01443
01444
01445 mSyncState = SYNC_STATE_HANDLE_INBOX;
01446 }
01447 mProgress += 5;
01448 serverSyncInternal();
01449 }
01450
01451
01452
01453 void KMFolderCachedImap::listMessages() {
01454 if( imapPath() == "/" ) {
01455
01456 serverSyncInternal();
01457 return;
01458 }
01459
01460 if( !mAccount->slave() ) {
01461 resetSyncState();
01462 emit folderComplete( this, false );
01463 return;
01464 }
01465 uidsOnServer.clear();
01466 uidsOnServer.resize( count() * 2 );
01467 uidsForDeletionOnServer.clear();
01468 mMsgsForDownload.clear();
01469 mUidsForDownload.clear();
01470
01471 mFoundAnIMAPDigest = false;
01472
01473 CachedImapJob* job = new CachedImapJob( FolderJob::tListMessages, this );
01474 connect( job, SIGNAL( result(KMail::FolderJob *) ),
01475 this, SLOT( slotGetLastMessagesResult(KMail::FolderJob *) ) );
01476 job->start();
01477 }
01478
01479 void KMFolderCachedImap::slotGetLastMessagesResult(KMail::FolderJob *job)
01480 {
01481 getMessagesResult(job, true);
01482 }
01483
01484
01485 void KMFolderCachedImap::slotGetMessagesData(KIO::Job * job, const QByteArray & data)
01486 {
01487 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
01488 if ( it == mAccount->jobsEnd() ) {
01489 kdDebug(5006) << "could not find job!?!?!" << endl;
01490
01491
01492
01493 mSyncState = SYNC_STATE_HANDLE_INBOX;
01494 serverSyncInternal();
01495 return;
01496 }
01497 (*it).cdata += QCString(data, data.size() + 1);
01498 int pos = (*it).cdata.find("\r\n--IMAPDIGEST");
01499 if (pos > 0) {
01500 int a = (*it).cdata.find("\r\nX-uidValidity:");
01501 if (a != -1) {
01502 int b = (*it).cdata.find("\r\n", a + 17);
01503 setUidValidity((*it).cdata.mid(a + 17, b - a - 17));
01504 }
01505 a = (*it).cdata.find("\r\nX-Access:");
01506
01507
01508
01509
01510
01511 if (a != -1 && mUserRights == -1 ) {
01512 int b = (*it).cdata.find("\r\n", a + 12);
01513 const QString access = (*it).cdata.mid(a + 12, b - a - 12);
01514 setReadOnly( access == "Read only" );
01515 }
01516 (*it).cdata.remove(0, pos);
01517 mFoundAnIMAPDigest = true;
01518 }
01519 pos = (*it).cdata.find("\r\n--IMAPDIGEST", 1);
01520
01521 if ( uidsOnServer.size() == 0 )
01522 uidsOnServer.resize( KMail::nextPrime( 2000 ) );
01523 int flags;
01524 const int v = 42;
01525 while (pos >= 0) {
01526 KMMessage msg;
01527 msg.fromString((*it).cdata.mid(16, pos - 16));
01528 flags = msg.headerField("X-Flags").toInt();
01529 bool deleted = ( flags & 8 );
01530 ulong uid = msg.UID();
01531 if ( !deleted ) {
01532 if( uid != 0 ) {
01533 if ( uidsOnServer.count() == uidsOnServer.size() ) {
01534 uidsOnServer.resize( KMail::nextPrime( uidsOnServer.size() * 2 ) );
01535
01536 }
01537 uidsOnServer.insert( uid, &v );
01538 }
01539 bool redownload = false;
01540 if ( uid <= lastUid() ) {
01541
01542
01543
01544
01545
01546
01547
01548
01549
01550
01551 KMMsgBase *existingMessage = findByUID(uid);
01552 if( !existingMessage ) {
01553 if ( mUserRights <= 0 || ( mUserRights & KMail::ACLJobs::Delete ) ) {
01554 #if MAIL_LOSS_DEBUGGING
01555 kdDebug(5006) << "message with uid " << uid << " is gone from local cache. Must be deleted on server!!!" << endl;
01556 #endif
01557 uidsForDeletionOnServer << uid;
01558 } else {
01559 redownload = true;
01560 }
01561 } else {
01562
01563
01564
01565 if (!mReadOnly) {
01566
01567 KMFolderImap::flagsToStatus( existingMessage, flags );
01568 }
01569 }
01570
01571 }
01572 if ( uid > lastUid() || redownload ) {
01573
01574
01575 if ( !uidMap.contains( uid ) ) {
01576 ulong size = msg.headerField("X-Length").toULong();
01577 mMsgsForDownload << KMail::CachedImapJob::MsgForDownload(uid, flags, size);
01578 if( imapPath() == "/INBOX/" )
01579 mUidsForDownload << uid;
01580 }
01581
01582 if ( uid > mTentativeHighestUid )
01583 mTentativeHighestUid = uid;
01584 }
01585 }
01586 (*it).cdata.remove(0, pos);
01587 (*it).done++;
01588 pos = (*it).cdata.find("\r\n--IMAPDIGEST", 1);
01589 }
01590 }
01591
01592 void KMFolderCachedImap::getMessagesResult( KMail::FolderJob *job, bool lastSet )
01593 {
01594 mProgress += 10;
01595 if ( !job->error() && !mFoundAnIMAPDigest ) {
01596 kdWarning(5006) << "######## Folderlisting did not complete, but there was no error! "
01597 "Aborting sync of folder: " << folder()->prettyURL() << endl;
01598 #if MAIL_LOSS_DEBUGGING
01599 kmkernel->emergencyExit( i18n("Folder listing failed in interesting ways." ) );
01600 #endif
01601 }
01602 if( job->error() ) {
01603 mContentState = imapNoInformation;
01604 mSyncState = SYNC_STATE_HANDLE_INBOX;
01605 } else {
01606 if( lastSet ) {
01607 mContentState = imapFinished;
01608 mStatusChangedLocally = false;
01609 }
01610 }
01611 serverSyncInternal();
01612 }
01613
01614 void KMFolderCachedImap::slotProgress(unsigned long done, unsigned long total)
01615 {
01616 int progressSpan = 100 - 5 - mProgress;
01617
01618
01619
01620 newState( mProgress + (progressSpan * done) / total, QString::null );
01621 }
01622
01623
01624 void KMFolderCachedImap::setAccount(KMAcctCachedImap *aAccount)
01625 {
01626 assert( aAccount->isA("KMAcctCachedImap") );
01627 mAccount = aAccount;
01628 if( imapPath()=="/" ) aAccount->setFolder( folder() );
01629
01630
01631 QString newName = mAccount->renamedFolder( imapPath() );
01632 if ( !newName.isEmpty() )
01633 folder()->setLabel( newName );
01634
01635 if( !folder() || !folder()->child() || !folder()->child()->count() ) return;
01636 for( KMFolderNode* node = folder()->child()->first(); node;
01637 node = folder()->child()->next() )
01638 if (!node->isDir())
01639 static_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage())->setAccount(aAccount);
01640 }
01641
01642 void KMFolderCachedImap::listNamespaces()
01643 {
01644 ImapAccountBase::ListType type = ImapAccountBase::List;
01645 if ( mAccount->onlySubscribedFolders() )
01646 type = ImapAccountBase::ListSubscribed;
01647
01648 kdDebug(5006) << "listNamespaces " << mNamespacesToList << endl;
01649 if ( mNamespacesToList.isEmpty() ) {
01650 mSyncState = SYNC_STATE_DELETE_SUBFOLDERS;
01651 mPersonalNamespacesCheckDone = true;
01652
01653 QStringList ns = mAccount->namespaces()[ImapAccountBase::OtherUsersNS];
01654 ns += mAccount->namespaces()[ImapAccountBase::SharedNS];
01655 mNamespacesToCheck = ns.count();
01656 for ( QStringList::Iterator it = ns.begin(); it != ns.end(); ++it )
01657 {
01658 if ( (*it).isEmpty() ) {
01659
01660 --mNamespacesToCheck;
01661 continue;
01662 }
01663 KMail::ListJob* job = new KMail::ListJob( mAccount, type, this, mAccount->addPathToNamespace( *it ) );
01664 connect( job, SIGNAL(receivedFolders(const QStringList&, const QStringList&,
01665 const QStringList&, const QStringList&, const ImapAccountBase::jobData&)),
01666 this, SLOT(slotCheckNamespace(const QStringList&, const QStringList&,
01667 const QStringList&, const QStringList&, const ImapAccountBase::jobData&)));
01668 job->start();
01669 }
01670 if ( mNamespacesToCheck == 0 ) {
01671 serverSyncInternal();
01672 }
01673 return;
01674 }
01675 mPersonalNamespacesCheckDone = false;
01676
01677 QString ns = mNamespacesToList.front();
01678 mNamespacesToList.pop_front();
01679
01680 mSyncState = SYNC_STATE_LIST_SUBFOLDERS2;
01681 newState( mProgress, i18n("Retrieving folders for namespace %1").arg(ns));
01682 KMail::ListJob* job = new KMail::ListJob( mAccount, type, this,
01683 mAccount->addPathToNamespace( ns ) );
01684 job->setNamespace( ns );
01685 connect( job, SIGNAL(receivedFolders(const QStringList&, const QStringList&,
01686 const QStringList&, const QStringList&, const ImapAccountBase::jobData&)),
01687 this, SLOT(slotListResult(const QStringList&, const QStringList&,
01688 const QStringList&, const QStringList&, const ImapAccountBase::jobData&)));
01689 job->start();
01690 }
01691
01692 void KMFolderCachedImap::slotCheckNamespace( const QStringList& subfolderNames,
01693 const QStringList& subfolderPaths,
01694 const QStringList& subfolderMimeTypes,
01695 const QStringList& subfolderAttributes,
01696 const ImapAccountBase::jobData& jobData )
01697 {
01698 Q_UNUSED( subfolderPaths );
01699 Q_UNUSED( subfolderMimeTypes );
01700 Q_UNUSED( subfolderAttributes );
01701 --mNamespacesToCheck;
01702 kdDebug(5006) << "slotCheckNamespace " << subfolderNames << ",remain=" <<
01703 mNamespacesToCheck << endl;
01704
01705
01706
01707 QString name = jobData.path.mid( 1, jobData.path.length()-2 );
01708 name.remove( mAccount->delimiterForNamespace( name ) );
01709 if ( name.isEmpty() ) {
01710
01711 kdWarning(5006) << "slotCheckNamespace: ignoring empty folder!" << endl;
01712 return;
01713 }
01714
01715 folder()->createChildFolder();
01716 KMFolderNode *node = 0;
01717 for ( node = folder()->child()->first(); node;
01718 node = folder()->child()->next())
01719 {
01720 if ( !node->isDir() && node->name() == name )
01721 break;
01722 }
01723 if ( !subfolderNames.isEmpty() ) {
01724 if ( node ) {
01725
01726 kdDebug(5006) << "found namespace folder " << name << endl;
01727 } else
01728 {
01729
01730 kdDebug(5006) << "create namespace folder " << name << endl;
01731 KMFolder* newFolder = folder()->child()->createFolder( name, false,
01732 KMFolderTypeCachedImap );
01733 if ( newFolder ) {
01734 KMFolderCachedImap *f = static_cast<KMFolderCachedImap*>( newFolder->storage() );
01735 f->setImapPath( mAccount->addPathToNamespace( name ) );
01736 f->setNoContent( true );
01737 f->setAccount( mAccount );
01738 f->close();
01739 kmkernel->dimapFolderMgr()->contentsChanged();
01740 }
01741 }
01742 } else {
01743 if ( node ) {
01744 kdDebug(5006) << "delete namespace folder " << name << endl;
01745 KMFolder* fld = static_cast<KMFolder*>(node);
01746 kmkernel->dimapFolderMgr()->remove( fld );
01747 }
01748 }
01749
01750 if ( mNamespacesToCheck == 0 ) {
01751
01752 serverSyncInternal();
01753 }
01754 }
01755
01756
01757
01758 bool KMFolderCachedImap::listDirectory()
01759 {
01760 if( !mAccount->slave() ) {
01761 resetSyncState();
01762 emit folderComplete( this, false );
01763 return false;
01764 }
01765 mSubfolderState = imapInProgress;
01766
01767
01768 ImapAccountBase::ListType type = ImapAccountBase::List;
01769 if ( mAccount->onlySubscribedFolders() )
01770 type = ImapAccountBase::ListSubscribed;
01771 KMail::ListJob* job = new KMail::ListJob( mAccount, type, this );
01772 connect( job, SIGNAL(receivedFolders(const QStringList&, const QStringList&,
01773 const QStringList&, const QStringList&, const ImapAccountBase::jobData&)),
01774 this, SLOT(slotListResult(const QStringList&, const QStringList&,
01775 const QStringList&, const QStringList&, const ImapAccountBase::jobData&)));
01776 job->start();
01777
01778 return true;
01779 }
01780
01781 void KMFolderCachedImap::slotListResult( const QStringList& folderNames,
01782 const QStringList& folderPaths,
01783 const QStringList& folderMimeTypes,
01784 const QStringList& folderAttributes,
01785 const ImapAccountBase::jobData& jobData )
01786 {
01787 Q_UNUSED( jobData );
01788
01789
01790 mSubfolderNames = folderNames;
01791 mSubfolderPaths = folderPaths;
01792 mSubfolderMimeTypes = folderMimeTypes;
01793 mSubfolderAttributes = folderAttributes;
01794
01795 mSubfolderState = imapFinished;
01796
01797 folder()->createChildFolder();
01798 KMFolderNode *node = folder()->child()->first();
01799 bool root = ( this == mAccount->rootFolder() );
01800
01801 QPtrList<KMFolder> toRemove;
01802 bool emptyList = ( root && mSubfolderNames.empty() );
01803 if ( !emptyList ) {
01804 while (node) {
01805 if (!node->isDir() ) {
01806 KMFolderCachedImap *f = static_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage());
01807
01808 if ( mSubfolderNames.findIndex(node->name()) == -1 ) {
01809 QString name = node->name();
01810
01811
01812 bool isInNamespace = ( jobData.curNamespace.isEmpty() ||
01813 jobData.curNamespace == mAccount->namespaceForFolder( f ) );
01814
01815 bool ignore = root && ( f->imapPath() == "/INBOX/" ||
01816 mAccount->isNamespaceFolder( name ) || !isInNamespace );
01817
01818
01819 if( !f->imapPath().isEmpty() && !ignore ) {
01820
01821
01822 toRemove.append( f->folder() );
01823 kdDebug(5006) << node->name() << " isn't on the server. It has an imapPath -> delete it locally" << endl;
01824 }
01825 } else {
01826
01827 }
01828 } else {
01829
01830 }
01831 node = folder()->child()->next();
01832 }
01833 }
01834
01835 for ( KMFolder* doomed=toRemove.first(); doomed; doomed = toRemove.next() ) {
01836 kmkernel->dimapFolderMgr()->remove( doomed );
01837 }
01838
01839 mProgress += 5;
01840 serverSyncInternal();
01841 }
01842
01843
01844 void KMFolderCachedImap::listDirectory2()
01845 {
01846 QString path = folder()->path();
01847 KMFolderCachedImap *f = 0;
01848 kmkernel->dimapFolderMgr()->quiet(true);
01849
01850 KMFolderNode *node;
01851 bool root = ( this == mAccount->rootFolder() );
01852 if ( root && !mAccount->hasInbox() ) {
01853
01854
01855 for (node = folder()->child()->first(); node; node = folder()->child()->next())
01856 if (!node->isDir() && node->name() == "INBOX") break;
01857 if (node) {
01858 f = static_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage());
01859 } else {
01860 KMFolder* newFolder = folder()->child()->createFolder("INBOX", true, KMFolderTypeCachedImap);
01861 if ( newFolder ) {
01862 f = static_cast<KMFolderCachedImap*>(newFolder->storage());
01863 }
01864 }
01865 if ( f ) {
01866 f->setAccount( mAccount );
01867 f->setImapPath( "/INBOX/" );
01868 f->folder()->setLabel( i18n("inbox") );
01869 }
01870 if (!node) {
01871 if ( f )
01872 f->close();
01873 kmkernel->dimapFolderMgr()->contentsChanged();
01874 }
01875
01876 mAccount->setHasInbox( true );
01877 }
01878
01879 if ( root && !mSubfolderNames.isEmpty() ) {
01880 KMFolderCachedImap* parent =
01881 findParent( mSubfolderPaths.first(), mSubfolderNames.first() );
01882 if ( parent ) {
01883 kdDebug(5006) << "KMFolderCachedImap::listDirectory2 - pass listing to "
01884 << parent->label() << endl;
01885 mSubfolderNames.clear();
01886 }
01887 }
01888
01889
01890 for (uint i = 0; i < mSubfolderNames.count(); i++) {
01891
01892
01893 for (node = folder()->child()->first(); node;
01894 node = folder()->child()->next())
01895 if (!node->isDir() && node->name() == mSubfolderNames[i]) break;
01896
01897 if (!node) {
01898
01899
01900 QString subfolderPath = mSubfolderPaths[i];
01901
01902
01903
01904 bool locallyDeleted = mAccount->isDeletedFolder( subfolderPath );
01905
01906
01907
01908 if ( !locallyDeleted && mAccount->isPreviouslyDeletedFolder( subfolderPath ) ) {
01909 locallyDeleted = KMessageBox::warningYesNo(
01910 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;
01911 }
01912
01913 if ( locallyDeleted ) {
01914 kdDebug(5006) << subfolderPath << " was deleted locally => delete on server." << endl;
01915 foldersForDeletionOnServer += mAccount->deletedFolderPaths( subfolderPath );
01916 } else {
01917 kdDebug(5006) << subfolderPath << " is a new folder on the server => create local cache" << endl;
01918 KMFolder* newFolder = folder()->child()->createFolder(mSubfolderNames[i], false, KMFolderTypeCachedImap);
01919 if ( newFolder ) {
01920 f = static_cast<KMFolderCachedImap*>(newFolder->storage());
01921 }
01922 if (f) {
01923 f->close();
01924 f->setAccount(mAccount);
01925 kmkernel->dimapFolderMgr()->contentsChanged();
01926 f->mAnnotationFolderType = "FROMSERVER";
01927
01928 } else {
01929 kdDebug(5006) << "can't create folder " << mSubfolderNames[i] <<endl;
01930 }
01931 }
01932 } else {
01933 if( static_cast<KMFolder*>(node)->folderType() == KMFolderTypeCachedImap )
01934 f = static_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage());
01935 }
01936
01937 if( f ) {
01938
01939
01940
01941 f->setAccount(mAccount);
01942 f->setNoContent(mSubfolderMimeTypes[i] == "inode/directory");
01943 f->setNoChildren(mSubfolderMimeTypes[i] == "message/digest");
01944 f->setImapPath(mSubfolderPaths[i]);
01945 }
01946 }
01947 kmkernel->dimapFolderMgr()->quiet(false);
01948 emit listComplete(this);
01949 if ( !mPersonalNamespacesCheckDone ) {
01950
01951 mSyncState = SYNC_STATE_LIST_NAMESPACES;
01952 }
01953 serverSyncInternal();
01954 }
01955
01956
01957 KMFolderCachedImap* KMFolderCachedImap::findParent( const QString& path,
01958 const QString& name )
01959 {
01960 QString parent = path.left( path.length() - name.length() - 2 );
01961 if ( parent.length() > 1 )
01962 {
01963
01964 parent = parent.right( parent.length() - 1 );
01965 if ( parent != label() )
01966 {
01967 KMFolderNode *node = folder()->child()->first();
01968
01969 while ( node )
01970 {
01971 if ( node->name() == parent )
01972 {
01973 KMFolder* fld = static_cast<KMFolder*>(node);
01974 KMFolderCachedImap* imapFld =
01975 static_cast<KMFolderCachedImap*>( fld->storage() );
01976 return imapFld;
01977 }
01978 node = folder()->child()->next();
01979 }
01980 }
01981 }
01982 return 0;
01983 }
01984
01985 void KMFolderCachedImap::slotSubFolderComplete(KMFolderCachedImap* sub, bool success)
01986 {
01987 Q_UNUSED(sub);
01988
01989 if ( success ) {
01990 serverSyncInternal();
01991 }
01992 else
01993 {
01994
01995 if ( mCurrentSubfolder ) {
01996 Q_ASSERT( sub == mCurrentSubfolder );
01997 disconnect( mCurrentSubfolder, SIGNAL( folderComplete(KMFolderCachedImap*, bool) ),
01998 this, SLOT( slotSubFolderComplete(KMFolderCachedImap*, bool) ) );
01999 mCurrentSubfolder = 0;
02000 }
02001
02002 mSubfoldersForSync.clear();
02003 mSyncState = SYNC_STATE_INITIAL;
02004 close();
02005 emit folderComplete( this, false );
02006 }
02007 }
02008
02009 void KMFolderCachedImap::slotSimpleData(KIO::Job * job, const QByteArray & data)
02010 {
02011 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
02012 if (it == mAccount->jobsEnd()) return;
02013 QBuffer buff((*it).data);
02014 buff.open(IO_WriteOnly | IO_Append);
02015 buff.writeBlock(data.data(), data.size());
02016 buff.close();
02017 }
02018
02019
02020 FolderJob*
02021 KMFolderCachedImap::doCreateJob( KMMessage *msg, FolderJob::JobType jt, KMFolder *folder,
02022 QString, const AttachmentStrategy* ) const
02023 {
02024 QPtrList<KMMessage> msgList;
02025 msgList.append( msg );
02026 CachedImapJob *job = new CachedImapJob( msgList, jt, folder? static_cast<KMFolderCachedImap*>( folder->storage() ):0 );
02027 job->setParentFolder( this );
02028 return job;
02029 }
02030
02031 FolderJob*
02032 KMFolderCachedImap::doCreateJob( QPtrList<KMMessage>& msgList, const QString& sets,
02033 FolderJob::JobType jt, KMFolder *folder ) const
02034 {
02035
02036 Q_UNUSED( sets );
02037 CachedImapJob *job = new CachedImapJob( msgList, jt, folder? static_cast<KMFolderCachedImap*>( folder->storage() ):0 );
02038 job->setParentFolder( this );
02039 return job;
02040 }
02041
02042 void
02043 KMFolderCachedImap::setUserRights( unsigned int userRights )
02044 {
02045 mUserRights = userRights;
02046 writeConfigKeysWhichShouldNotGetOverwrittenByReadConfig();
02047 }
02048
02049 void
02050 KMFolderCachedImap::slotReceivedUserRights( KMFolder* folder )
02051 {
02052 if ( folder->storage() == this ) {
02053 disconnect( mAccount, SIGNAL( receivedUserRights( KMFolder* ) ),
02054 this, SLOT( slotReceivedUserRights( KMFolder* ) ) );
02055 if ( mUserRights == 0 )
02056 mUserRights = -1;
02057 else
02058 setReadOnly( ( mUserRights & KMail::ACLJobs::Insert ) == 0 );
02059 mProgress += 5;
02060 serverSyncInternal();
02061 }
02062 }
02063
02064 void
02065 KMFolderCachedImap::setReadOnly( bool readOnly )
02066 {
02067 if ( readOnly != mReadOnly ) {
02068 mReadOnly = readOnly;
02069 emit readOnlyChanged( folder() );
02070 }
02071 }
02072
02073 void
02074 KMFolderCachedImap::slotReceivedACL( KMFolder* folder, KIO::Job*, const KMail::ACLList& aclList )
02075 {
02076 if ( folder->storage() == this ) {
02077 disconnect( mAccount, SIGNAL(receivedACL( KMFolder*, KIO::Job*, const KMail::ACLList& )),
02078 this, SLOT(slotReceivedACL( KMFolder*, KIO::Job*, const KMail::ACLList& )) );
02079 mACLList = aclList;
02080 serverSyncInternal();
02081 }
02082 }
02083
02084 void
02085 KMFolderCachedImap::slotStorageQuotaResult( const QuotaInfo& info )
02086 {
02087 mQuotaInfo = info;
02088 writeConfigKeysWhichShouldNotGetOverwrittenByReadConfig();
02089 }
02090
02091 void
02092 KMFolderCachedImap::setACLList( const ACLList& arr )
02093 {
02094 mACLList = arr;
02095 }
02096
02097 void
02098 KMFolderCachedImap::slotMultiSetACLResult(KIO::Job *job)
02099 {
02100 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
02101 if ( it == mAccount->jobsEnd() ) return;
02102 if ( (*it).parent != folder() ) return;
02103
02104 if ( job->error() )
02105
02106
02107 job->showErrorDialog();
02108 else
02109 kmkernel->iCalIface().addFolderChange( folder(), KMailICalIfaceImpl::ACL );
02110
02111 if (mAccount->slave()) mAccount->removeJob(job);
02112 serverSyncInternal();
02113 }
02114
02115 void
02116 KMFolderCachedImap::slotACLChanged( const QString& userId, int permissions )
02117 {
02118
02119
02120 for( ACLList::Iterator it = mACLList.begin(); it != mACLList.end(); ++it ) {
02121 if ( (*it).userId == userId && (*it).permissions == permissions ) {
02122 if ( permissions == -1 )
02123 mACLList.erase( it );
02124 else
02125 (*it).changed = false;
02126 return;
02127 }
02128 }
02129 }
02130
02131
02132 void KMFolderCachedImap::resetSyncState()
02133 {
02134 if ( mSyncState == SYNC_STATE_INITIAL ) return;
02135 mSubfoldersForSync.clear();
02136 mSyncState = SYNC_STATE_INITIAL;
02137 close();
02138
02139 KPIM::ProgressItem *progressItem = mAccount->mailCheckProgressItem();
02140 QString str = i18n("Aborted");
02141 if (progressItem)
02142 progressItem->setStatus( str );
02143 emit statusMsg( str );
02144 }
02145
02146 void KMFolderCachedImap::slotIncreaseProgress()
02147 {
02148 mProgress += 5;
02149 }
02150
02151 void KMFolderCachedImap::newState( int progress, const QString& syncStatus )
02152 {
02153
02154 KPIM::ProgressItem *progressItem = mAccount->mailCheckProgressItem();
02155 if( progressItem )
02156 progressItem->setCompletedItems( progress );
02157 if ( !syncStatus.isEmpty() ) {
02158 QString str;
02159
02160 if ( mAccount->imapFolder() == this )
02161 str = syncStatus;
02162 else
02163 str = QString( "%1: %2" ).arg( label() ).arg( syncStatus );
02164 if( progressItem )
02165 progressItem->setStatus( str );
02166 emit statusMsg( str );
02167 }
02168 if( progressItem )
02169 progressItem->updateProgress();
02170 }
02171
02172 void KMFolderCachedImap::setSubfolderState( imapState state )
02173 {
02174 mSubfolderState = state;
02175 if ( state == imapNoInformation && folder()->child() )
02176 {
02177
02178 KMFolderNode* node;
02179 QPtrListIterator<KMFolderNode> it( *folder()->child() );
02180 for ( ; (node = it.current()); )
02181 {
02182 ++it;
02183 if (node->isDir()) continue;
02184 KMFolder *folder = static_cast<KMFolder*>(node);
02185 static_cast<KMFolderCachedImap*>(folder->storage())->setSubfolderState( state );
02186 }
02187 }
02188 }
02189
02190 void KMFolderCachedImap::setImapPath(const QString &path)
02191 {
02192 mImapPath = path;
02193 }
02194
02195
02196
02197
02198
02199
02200 void KMFolderCachedImap::updateAnnotationFolderType()
02201 {
02202 QString oldType = mAnnotationFolderType;
02203 QString oldSubType;
02204 int dot = oldType.find( '.' );
02205 if ( dot != -1 ) {
02206 oldType.truncate( dot );
02207 oldSubType = mAnnotationFolderType.mid( dot + 1 );
02208 }
02209
02210 QString newType, newSubType;
02211
02212 if ( kmkernel->iCalIface().storageFormat( folder() ) == KMailICalIfaceImpl::StorageXML ) {
02213 newType = KMailICalIfaceImpl::annotationForContentsType( mContentsType );
02214 if ( kmkernel->iCalIface().isStandardResourceFolder( folder() ) )
02215 newSubType = "default";
02216 else
02217 newSubType = oldSubType;
02218 }
02219
02220
02221 if ( newType != oldType || newSubType != oldSubType ) {
02222 mAnnotationFolderType = newType + ( newSubType.isEmpty() ? QString::null : "."+newSubType );
02223 mAnnotationFolderTypeChanged = true;
02224 kdDebug(5006) << mImapPath << ": updateAnnotationFolderType: '" << mAnnotationFolderType << "', was (" << oldType << " " << oldSubType << ") => mAnnotationFolderTypeChanged set to TRUE" << endl;
02225 }
02226
02227 writeConfigKeysWhichShouldNotGetOverwrittenByReadConfig();
02228 }
02229
02230 void KMFolderCachedImap::setIncidencesFor( IncidencesFor incfor )
02231 {
02232 if ( mIncidencesFor != incfor ) {
02233 mIncidencesFor = incfor;
02234 mIncidencesForChanged = true;
02235 }
02236 }
02237
02238 void KMFolderCachedImap::slotAnnotationResult(const QString& entry, const QString& value, bool found)
02239 {
02240 if ( entry == KOLAB_FOLDERTYPE ) {
02241
02242
02243
02244
02245
02246 if ( found ) {
02247 QString type = value;
02248 QString subtype;
02249 int dot = value.find( '.' );
02250 if ( dot != -1 ) {
02251 type.truncate( dot );
02252 subtype = value.mid( dot + 1 );
02253 }
02254 bool foundKnownType = false;
02255 for ( uint i = 0 ; i <= ContentsTypeLast; ++i ) {
02256 FolderContentsType contentsType = static_cast<KMail::FolderContentsType>( i );
02257 if ( type == KMailICalIfaceImpl::annotationForContentsType( contentsType ) ) {
02258
02259
02260 if ( contentsType != ContentsTypeMail )
02261 kmkernel->iCalIface().setStorageFormat( folder(), KMailICalIfaceImpl::StorageXML );
02262 mAnnotationFolderType = value;
02263 if ( folder()->parent()->owner()->idString() != GlobalSettings::self()->theIMAPResourceFolderParent()
02264 && GlobalSettings::self()->theIMAPResourceEnabled()
02265 && subtype == "default" ) {
02266
02267
02268 mAnnotationFolderType = type;
02269 kdDebug(5006) << mImapPath << ": slotGetAnnotationResult: parent folder is " << folder()->parent()->owner()->idString() << " => truncating annotation to " << value << endl;
02270 }
02271 setContentsType( contentsType );
02272 mAnnotationFolderTypeChanged = false;
02273 foundKnownType = true;
02274
02275
02276
02277
02278
02279 if ( contentsType != ContentsTypeMail )
02280 markUnreadAsRead();
02281
02282
02283 writeConfigKeysWhichShouldNotGetOverwrittenByReadConfig();
02284 break;
02285 }
02286 }
02287 if ( !foundKnownType && !mReadOnly ) {
02288
02289
02290 mAnnotationFolderTypeChanged = true;
02291 }
02292
02293 }
02294 else if ( !mReadOnly ) {
02295
02296
02297 mAnnotationFolderTypeChanged = true;
02298 }
02299 } else if ( entry == KOLAB_INCIDENCESFOR ) {
02300 if ( found ) {
02301 mIncidencesFor = incidencesForFromString( value );
02302 Q_ASSERT( mIncidencesForChanged == false );
02303 }
02304 }
02305 }
02306
02307 void KMFolderCachedImap::slotGetAnnotationResult( KIO::Job* job )
02308 {
02309 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
02310 Q_ASSERT( it != mAccount->jobsEnd() );
02311 if ( it == mAccount->jobsEnd() ) return;
02312 Q_ASSERT( (*it).parent == folder() );
02313 if ( (*it).parent != folder() ) return;
02314
02315 AnnotationJobs::GetAnnotationJob* annjob = static_cast<AnnotationJobs::GetAnnotationJob *>( job );
02316 if ( annjob->error() ) {
02317 if ( job->error() == KIO::ERR_UNSUPPORTED_ACTION ) {
02318
02319 if ( GlobalSettings::self()->theIMAPResourceStorageFormat() == GlobalSettings::EnumTheIMAPResourceStorageFormat::XML
02320 && (uint)GlobalSettings::self()->theIMAPResourceAccount() == mAccount->id() )
02321 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() ) );
02322 mAccount->setHasNoAnnotationSupport();
02323 }
02324 else
02325 kdWarning(5006) << "slotGetAnnotationResult: " << job->errorString() << endl;
02326 }
02327
02328 if (mAccount->slave()) mAccount->removeJob(job);
02329 mProgress += 2;
02330 serverSyncInternal();
02331 }
02332
02333 void KMFolderCachedImap::slotQuotaResult( KIO::Job* job )
02334 {
02335 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
02336 Q_ASSERT( it != mAccount->jobsEnd() );
02337 if ( it == mAccount->jobsEnd() ) return;
02338 Q_ASSERT( (*it).parent == folder() );
02339 if ( (*it).parent != folder() ) return;
02340
02341 QuotaJobs::GetStorageQuotaJob* quotajob = static_cast<QuotaJobs::GetStorageQuotaJob *>( job );
02342 QuotaInfo empty;
02343 if ( quotajob->error() ) {
02344 if ( job->error() == KIO::ERR_UNSUPPORTED_ACTION ) {
02345
02346 mAccount->setHasNoQuotaSupport();
02347 mQuotaInfo = empty;
02348 }
02349 else
02350 kdWarning(5006) << "slotGetQuotaResult: " << job->errorString() << endl;
02351 }
02352
02353 if (mAccount->slave()) mAccount->removeJob(job);
02354 mProgress += 2;
02355 serverSyncInternal();
02356 }
02357
02358
02359
02360 void
02361 KMFolderCachedImap::slotAnnotationChanged( const QString& entry, const QString& attribute, const QString& value )
02362 {
02363 Q_UNUSED( attribute );
02364 Q_UNUSED( value );
02365
02366 if ( entry == KOLAB_FOLDERTYPE )
02367 mAnnotationFolderTypeChanged = false;
02368 else if ( entry == KOLAB_INCIDENCESFOR ) {
02369 mIncidencesForChanged = false;
02370
02371
02372 kmkernel->iCalIface().addFolderChange( folder(), KMailICalIfaceImpl::ACL );
02373 }
02374 }
02375
02376 void KMFolderCachedImap::slotTestAnnotationResult(KIO::Job *job)
02377 {
02378 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
02379 Q_ASSERT( it != mAccount->jobsEnd() );
02380 if ( it == mAccount->jobsEnd() ) return;
02381 Q_ASSERT( (*it).parent == folder() );
02382 if ( (*it).parent != folder() ) return;
02383
02384 mAccount->setAnnotationCheckPassed( true );
02385 if ( job->error() ) {
02386 kdDebug(5006) << "Test Annotation was not passed, disabling annotation support" << endl;
02387 mAccount->setHasNoAnnotationSupport( );
02388 } else {
02389 kdDebug(5006) << "Test Annotation was passed OK" << endl;
02390 }
02391 if (mAccount->slave()) mAccount->removeJob(job);
02392 serverSyncInternal();
02393 }
02394
02395 void
02396 KMFolderCachedImap::slotSetAnnotationResult(KIO::Job *job)
02397 {
02398 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
02399 if ( it == mAccount->jobsEnd() ) return;
02400 if ( (*it).parent != folder() ) return;
02401
02402 bool cont = true;
02403 if ( job->error() ) {
02404
02405 if ( job->error() == KIO::ERR_UNSUPPORTED_ACTION && contentsType() == ContentsTypeMail )
02406 if (mAccount->slave()) mAccount->removeJob(job);
02407 else
02408 cont = mAccount->handleJobError( job, i18n( "Error while setting annotation: " ) + '\n' );
02409 } else {
02410 if (mAccount->slave()) mAccount->removeJob(job);
02411 }
02412 if ( cont )
02413 serverSyncInternal();
02414 }
02415
02416 void KMFolderCachedImap::slotUpdateLastUid()
02417 {
02418 if( mTentativeHighestUid != 0 )
02419 setLastUid( mTentativeHighestUid );
02420 mTentativeHighestUid = 0;
02421 }
02422
02423 bool KMFolderCachedImap::isMoveable() const
02424 {
02425 return ( hasChildren() == HasNoChildren &&
02426 !folder()->isSystemFolder() ) ? true : false;
02427 }
02428
02429 void KMFolderCachedImap::slotFolderDeletionOnServerFinished()
02430 {
02431 for ( QStringList::const_iterator it = foldersForDeletionOnServer.constBegin();
02432 it != foldersForDeletionOnServer.constEnd(); ++it ) {
02433 KURL url( mAccount->getUrl() );
02434 url.setPath( *it );
02435 kmkernel->iCalIface().folderDeletedOnServer( url );
02436 }
02437 serverSyncInternal();
02438 }
02439
02440 #include "kmfoldercachedimap.moc"