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