00001
00032 #ifdef HAVE_CONFIG_H
00033 #include <config.h>
00034 #endif
00035
00036 #include <errno.h>
00037
00038 #include "kmkernel.h"
00039 #include "kmfoldercachedimap.h"
00040 #include "undostack.h"
00041 #include "kmfoldermgr.h"
00042 #include "kmmessage.h"
00043 #include "kmacctcachedimap.h"
00044 #include "kmacctmgr.h"
00045 #include "kmailicalifaceimpl.h"
00046 #include "kmfolder.h"
00047 #include "kmdict.h"
00048 #include "acljobs.h"
00049 #include "broadcaststatus.h"
00050 using KPIM::BroadcastStatus;
00051 #include "progressmanager.h"
00052
00053 using KMail::CachedImapJob;
00054 using KMail::ImapAccountBase;
00055 #include "listjob.h"
00056 using KMail::ListJob;
00057
00058 #include <kapplication.h>
00059 #include <kmessagebox.h>
00060 #include <klocale.h>
00061 #include <kdebug.h>
00062 #include <kconfig.h>
00063 #include <kio/global.h>
00064 #include <kio/scheduler.h>
00065 #include <qbuffer.h>
00066 #include <qfile.h>
00067 #include <qlabel.h>
00068 #include <qlayout.h>
00069 #include <qvaluelist.h>
00070
00071 #define UIDCACHE_VERSION 1
00072
00073
00074 DImapTroubleShootDialog::DImapTroubleShootDialog( QWidget* parent,
00075 const char* name )
00076 : KDialogBase( Plain, i18n( "Troubleshooting IMAP Cache" ),
00077 Cancel | User1 | User2, Cancel, parent, name, true ),
00078 rc( Cancel )
00079 {
00080 QFrame* page = plainPage();
00081 QVBoxLayout *topLayout = new QVBoxLayout( page, 0 );
00082 QString txt = i18n( "<p><b>Troubleshooting the IMAP cache.</b></p>"
00083 "<p>If you have problems with synchronizing an IMAP "
00084 "folder, you should first try rebuilding the index "
00085 "file. This will take some time to rebuild, but will "
00086 "not cause any problems.</p><p>If that is not enough, "
00087 "you can try refreshing the IMAP cache. If you do this, "
00088 "you will loose all your local changes for this folder "
00089 "and all it's subfolders.</p>" );
00090 topLayout->addWidget( new QLabel( txt, page ) );
00091 enableButtonSeparator( true );
00092
00093 setButtonText( User1, i18n( "Refresh &Cache" ) );
00094 setButtonText( User2, i18n( "Rebuild &Index" ) );
00095
00096 connect( this, SIGNAL( user1Clicked () ), this, SLOT( slotRebuildCache() ) );
00097 connect( this, SIGNAL( user2Clicked () ), this, SLOT( slotRebuildIndex() ) );
00098 }
00099
00100 int DImapTroubleShootDialog::run()
00101 {
00102 DImapTroubleShootDialog d;
00103 d.exec();
00104 return d.rc;
00105 }
00106
00107 void DImapTroubleShootDialog::slotRebuildCache()
00108 {
00109 rc = User1;
00110 done( User1 );
00111 }
00112
00113 void DImapTroubleShootDialog::slotRebuildIndex()
00114 {
00115 rc = User2;
00116 done( User2 );
00117 }
00118
00119
00120 KMFolderCachedImap::KMFolderCachedImap( KMFolder* folder, const char* aName )
00121 : KMFolderMaildir( folder, aName ),
00122 mSyncState( SYNC_STATE_INITIAL ), mContentState( imapNoInformation ),
00123 mSubfolderState( imapNoInformation ), mIsSelected( false ),
00124 mCheckFlags( true ), mAccount( NULL ), uidMapDirty( true ),
00125 uidWriteTimer( -1 ), mLastUid( 0 ), mTentativeHighestUid( 0 ),
00126 mUserRights( 0 ), mFolderRemoved( false ),
00127 mRecurse( true ),
00128 mContentsTypeChanged( false ), mStatusChangedLocally( false )
00129 {
00130 setUidValidity("");
00131 readUidCache();
00132
00133 mProgress = 0;
00134 }
00135
00136 KMFolderCachedImap::~KMFolderCachedImap()
00137 {
00138 if( !mFolderRemoved ) {
00139
00140 KConfig* config = KMKernel::config();
00141 KConfigGroupSaver saver( config, "Folder-" + folder()->idString() );
00142 config->writeEntry( "ImapPath", mImapPath );
00143 config->writeEntry( "NoContent", mNoContent );
00144 config->writeEntry( "ReadOnly", mReadOnly );
00145 config->writeEntry( "StatusChangedLocally", mStatusChangedLocally );
00146
00147 writeUidCache();
00148 }
00149
00150 if (kmkernel->undoStack()) kmkernel->undoStack()->folderDestroyed( folder() );
00151 }
00152
00153 void KMFolderCachedImap::initializeFrom( KMFolderCachedImap* parent )
00154 {
00155 setAccount( parent->account() );
00156
00157
00158 mAccount->removeDeletedFolder( imapPath() );
00159 setUserRights( parent->userRights() );
00160 }
00161
00162 void KMFolderCachedImap::readConfig()
00163 {
00164 KConfig* config = KMKernel::config();
00165 KConfigGroupSaver saver( config, "Folder-" + folder()->idString() );
00166 if( mImapPath.isEmpty() ) mImapPath = config->readEntry( "ImapPath" );
00167 if( QString( name() ).upper() == "INBOX" && mImapPath == "/INBOX/" )
00168 {
00169 folder()->setLabel( i18n( "inbox" ) );
00170
00171 folder()->setSystemFolder( true );
00172 }
00173 mNoContent = config->readBoolEntry( "NoContent", false );
00174 mReadOnly = config->readBoolEntry( "ReadOnly", false );
00175
00176 KMFolderMaildir::readConfig();
00177 mContentsTypeChanged = false;
00178 mStatusChangedLocally =
00179 config->readBoolEntry( "StatusChangedLocally", false );
00180 }
00181
00182 void KMFolderCachedImap::remove()
00183 {
00184 mFolderRemoved = true;
00185
00186 QString part1 = folder()->path() + "/." + dotEscape(name());
00187 QString uidCacheFile = part1 + ".uidcache";
00188
00189
00190 if( QFile::exists(uidCacheFile) )
00191 unlink( QFile::encodeName( uidCacheFile ) );
00192 KIO::del( KURL::fromPathOrURL( part1 + ".directory" ) );
00193
00194 FolderStorage::remove();
00195 }
00196
00197 QString KMFolderCachedImap::uidCacheLocation() const
00198 {
00199 QString sLocation(folder()->path());
00200 if (!sLocation.isEmpty()) sLocation += '/';
00201 return sLocation + '.' + dotEscape(fileName()) + ".uidcache";
00202 }
00203
00204 int KMFolderCachedImap::readUidCache()
00205 {
00206 QFile uidcache( uidCacheLocation() );
00207 if( uidcache.open( IO_ReadOnly ) ) {
00208 char buf[1024];
00209 int len = uidcache.readLine( buf, sizeof(buf) );
00210 if( len > 0 ) {
00211 int cacheVersion;
00212 sscanf( buf, "# KMail-UidCache V%d\n", &cacheVersion );
00213 if( cacheVersion == UIDCACHE_VERSION ) {
00214 len = uidcache.readLine( buf, sizeof(buf) );
00215 if( len > 0 ) {
00216 setUidValidity( QString::fromLocal8Bit( buf).stripWhiteSpace() );
00217 len = uidcache.readLine( buf, sizeof(buf) );
00218 if( len > 0 ) {
00219
00220 setLastUid( QString::fromLocal8Bit( buf).stripWhiteSpace().toULong() );
00221 return 0;
00222 }
00223 }
00224 }
00225 }
00226 }
00227 return -1;
00228 }
00229
00230 int KMFolderCachedImap::writeUidCache()
00231 {
00232 if( uidValidity().isEmpty() || uidValidity() == "INVALID" ) {
00233
00234 if( QFile::exists( uidCacheLocation() ) )
00235 unlink( QFile::encodeName( uidCacheLocation() ) );
00236 return 0;
00237 }
00238
00239 QFile uidcache( uidCacheLocation() );
00240 if( uidcache.open( IO_WriteOnly ) ) {
00241 QTextStream str( &uidcache );
00242 str << "# KMail-UidCache V" << UIDCACHE_VERSION << endl;
00243 str << uidValidity() << endl;
00244 str << lastUid() << endl;
00245 uidcache.flush();
00246 fsync( uidcache.handle() );
00247 uidcache.close();
00248 return 0;
00249 } else {
00250 return errno;
00251 }
00252 }
00253
00254 void KMFolderCachedImap::reloadUidMap()
00255 {
00256 uidMap.clear();
00257 open();
00258 for( int i = 0; i < count(); ++i ) {
00259 KMMsgBase *msg = getMsgBase( i );
00260 if( !msg ) continue;
00261 ulong uid = msg->UID();
00262 uidMap.insert( uid, i );
00263 }
00264 close();
00265 uidMapDirty = false;
00266 }
00267
00268
00269 KMMessage* KMFolderCachedImap::take(int idx)
00270 {
00271 uidMapDirty = true;
00272 return KMFolderMaildir::take(idx);
00273 }
00274
00275
00276 int KMFolderCachedImap::addMsgInternal( KMMessage* msg, bool newMail,
00277 int* index_return )
00278 {
00279
00280 ulong uid = msg->UID();
00281 if( uid != 0 ) {
00282 uidMapDirty = true;
00283 }
00284
00285
00286 int rc = KMFolderMaildir::addMsg(msg, index_return);
00287
00288 if( newMail && imapPath() == "/INBOX/" )
00289
00290 mAccount->processNewMsg( msg );
00291
00292 return rc;
00293 }
00294
00295
00296 int KMFolderCachedImap::addMsg(KMMessage* msg, int* index_return)
00297 {
00298
00299 msg->removeHeaderField( "X-UID" );
00300 msg->setUID( 0 );
00301
00302
00303 return addMsgInternal( msg, false, index_return );
00304 }
00305
00306
00307
00308 void KMFolderCachedImap::removeMsg(int idx, bool imapQuiet)
00309 {
00310 uidMapDirty = true;
00311
00312 KMFolderMaildir::removeMsg(idx,imapQuiet);
00313 }
00314
00315 bool KMFolderCachedImap::canRemoveFolder() const {
00316
00317 if( folder() && folder()->child() && folder()->child()->count() > 0 )
00318 return false;
00319
00320 #if 0
00321
00322 return KMFolderMaildir::canRemoveFolder();
00323 #endif
00324 return true;
00325 }
00326
00327
00328 int KMFolderCachedImap::rename( const QString& aName,
00329 KMFolderDir* )
00330 {
00331 if ( aName == name() )
00332
00333 return 0;
00334
00335 if( account() == 0 || imapPath().isEmpty() ) {
00336 QString err = i18n("You must synchronize with the server before renaming IMAP folders.");
00337 KMessageBox::error( 0, err );
00338 return -1;
00339 }
00340
00341
00342
00343 mAccount->addRenamedFolder( imapPath(), folder()->label(), aName );
00344 folder()->setLabel( aName );
00345
00346 return 0;
00347 }
00348
00349 KMFolder* KMFolderCachedImap::trashFolder() const
00350 {
00351 QString trashStr = account()->trash();
00352 return kmkernel->dimapFolderMgr()->findIdString( trashStr );
00353 }
00354
00355 void KMFolderCachedImap::setLastUid( ulong uid )
00356 {
00357 mLastUid = uid;
00358 if( uidWriteTimer == -1 )
00359
00360 uidWriteTimer = startTimer( 60000 );
00361 }
00362
00363 void KMFolderCachedImap::timerEvent( QTimerEvent* )
00364 {
00365 killTimer( uidWriteTimer );
00366 uidWriteTimer = -1;
00367 writeUidCache();
00368 }
00369
00370 ulong KMFolderCachedImap::lastUid()
00371 {
00372 return mLastUid;
00373 }
00374
00375 KMMsgBase* KMFolderCachedImap::findByUID( ulong uid )
00376 {
00377 bool mapReloaded = false;
00378 if( uidMapDirty ) {
00379 reloadUidMap();
00380 mapReloaded = true;
00381 }
00382
00383 QMap<ulong,int>::Iterator it = uidMap.find( uid );
00384 if( it != uidMap.end() ) {
00385 KMMsgBase *msg = getMsgBase( *it );
00386 if( msg && msg->UID() == uid )
00387 return msg;
00388 }
00389
00390 if( mapReloaded )
00391
00392 return 0;
00393
00394 reloadUidMap();
00395 it = uidMap.find( uid );
00396 if( it != uidMap.end() )
00397
00398 return getMsg( *it );
00399
00400 return 0;
00401 }
00402
00403
00404
00405 KMAcctCachedImap *KMFolderCachedImap::account() const
00406 {
00407 if( (KMAcctCachedImap *)mAccount == 0 ) {
00408
00409 mAccount = static_cast<KMAcctCachedImap *>( kmkernel->acctMgr()->findByName( name() ) );
00410 }
00411
00412 return mAccount;
00413 }
00414
00415 void KMFolderCachedImap::slotTroubleshoot()
00416 {
00417 const int rc = DImapTroubleShootDialog::run();
00418
00419 if( rc == KDialogBase::User1 ) {
00420
00421 if( !account() ) {
00422 KMessageBox::sorry( 0, i18n("No account setup for this folder.\n"
00423 "Please try running a sync before this.") );
00424 return;
00425 }
00426 QString str = i18n("Are you sure you want to refresh the IMAP cache of "
00427 "the folder %1 and all it's subfolders?\nThis will "
00428 "remove all changes you have done locally to your "
00429 "folders").arg( label() );
00430 QString s1 = i18n("Refresh IMAP Cache");
00431 QString s2 = i18n("&Refresh");
00432 if( KMessageBox::warningContinueCancel( 0, str, s1, s2 ) ==
00433 KMessageBox::Continue )
00434 account()->invalidateIMAPFolders( this );
00435 } else if( rc == KDialogBase::User2 ) {
00436
00437 createIndexFromContents();
00438 KMessageBox::information( 0, i18n( "The index of this folder has been "
00439 "recreated." ) );
00440 }
00441 }
00442
00443 void KMFolderCachedImap::serverSync( bool recurse )
00444 {
00445 if( mSyncState != SYNC_STATE_INITIAL ) {
00446 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 ) ) == KMessageBox::Yes ) {
00447 mSyncState = SYNC_STATE_INITIAL;
00448 } else return;
00449 }
00450
00451 mRecurse = recurse;
00452 assert( account() );
00453
00454 mAccount->mailCheckProgressItem()->reset();
00455 mAccount->mailCheckProgressItem()->setTotalItems( 100 );
00456 mProgress = 0;
00457
00458 #if 0
00459 if( mHoldSyncs ) {
00460
00461 account()->mailCheckProgressItem()->setProgress( 100 );
00462 mProgress = 100;
00463 newState( mProgress, i18n("Synchronization skipped"));
00464 mSyncState = SYNC_STATE_INITIAL;
00465 emit folderComplete( this, true );
00466 return;
00467 }
00468 #endif
00469 mTentativeHighestUid = 0;
00470
00471 serverSyncInternal();
00472 }
00473
00474 QString KMFolderCachedImap::state2String( int state ) const
00475 {
00476 switch( state ) {
00477 case SYNC_STATE_INITIAL: return "SYNC_STATE_INITIAL";
00478 case SYNC_STATE_PUT_MESSAGES: return "SYNC_STATE_PUT_MESSAGES";
00479 case SYNC_STATE_UPLOAD_FLAGS: return "SYNC_STATE_UPLOAD_FLAGS";
00480 case SYNC_STATE_CREATE_SUBFOLDERS: return "SYNC_STATE_CREATE_SUBFOLDERS";
00481 case SYNC_STATE_LIST_SUBFOLDERS: return "SYNC_STATE_LIST_SUBFOLDERS";
00482 case SYNC_STATE_LIST_SUBFOLDERS2: return "SYNC_STATE_LIST_SUBFOLDERS2";
00483 case SYNC_STATE_DELETE_SUBFOLDERS: return "SYNC_STATE_DELETE_SUBFOLDERS";
00484 case SYNC_STATE_LIST_MESSAGES: return "SYNC_STATE_LIST_MESSAGES";
00485 case SYNC_STATE_DELETE_MESSAGES: return "SYNC_STATE_DELETE_MESSAGES";
00486 case SYNC_STATE_GET_MESSAGES: return "SYNC_STATE_GET_MESSAGES";
00487 case SYNC_STATE_EXPUNGE_MESSAGES: return "SYNC_STATE_EXPUNGE_MESSAGES";
00488 case SYNC_STATE_HANDLE_INBOX: return "SYNC_STATE_HANDLE_INBOX";
00489 case SYNC_STATE_GET_USERRIGHTS: return "SYNC_STATE_GET_USERRIGHTS";
00490 case SYNC_STATE_GET_ACLS: return "SYNC_STATE_GET_ACLS";
00491 case SYNC_STATE_SET_ACLS: return "SYNC_STATE_SET_ACLS";
00492 case SYNC_STATE_FIND_SUBFOLDERS: return "SYNC_STATE_FIND_SUBFOLDERS";
00493 case SYNC_STATE_SYNC_SUBFOLDERS: return "SYNC_STATE_SYNC_SUBFOLDERS";
00494 case SYNC_STATE_CHECK_UIDVALIDITY: return "SYNC_STATE_CHECK_UIDVALIDITY";
00495 case SYNC_STATE_RENAME_FOLDER: return "SYNC_STATE_RENAME_FOLDER";
00496 default: return "Unknown state";
00497 }
00498 }
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528 void KMFolderCachedImap::serverSyncInternal()
00529 {
00530
00531
00532
00533 if( kmkernel->mailCheckAborted() ) {
00534 resetSyncState();
00535 emit folderComplete( this, false );
00536 return;
00537 }
00538
00539
00540 switch( mSyncState ) {
00541 case SYNC_STATE_INITIAL:
00542 {
00543 mProgress = 0;
00544 newState( mProgress, i18n("Synchronizing"));
00545
00546 open();
00547 if ( !noContent() )
00548 mAccount->addLastUnreadMsgCount( this, countUnread() );
00549
00550
00551 ImapAccountBase::ConnectionState cs = mAccount->makeConnection();
00552 if ( cs == ImapAccountBase::Error ) {
00553
00554
00555
00556 newState( mProgress, i18n( "Error connecting to server %1" ).arg( mAccount->host() ) );
00557 close();
00558 emit folderComplete(this, FALSE);
00559 break;
00560 } else if ( cs == ImapAccountBase::Connecting ) {
00561
00562 newState( mProgress, i18n("Connecting to %1").arg( mAccount->host() ) );
00563
00564 connect( mAccount, SIGNAL( connectionResult(int, const QString&) ),
00565 this, SLOT( slotConnectionResult(int, const QString&) ) );
00566 break;
00567 } else {
00568
00569
00570 mSyncState = SYNC_STATE_GET_USERRIGHTS;
00571
00572 }
00573 }
00574
00575 case SYNC_STATE_GET_USERRIGHTS:
00576 mSyncState = SYNC_STATE_RENAME_FOLDER;
00577
00578 if( !noContent() && mAccount->hasACLSupport() ) {
00579
00580 newState( mProgress, i18n("Checking permissions"));
00581 connect( mAccount, SIGNAL( receivedUserRights( KMFolder* ) ),
00582 this, SLOT( slotReceivedUserRights( KMFolder* ) ) );
00583 mAccount->getUserRights( folder(), imapPath() );
00584 break;
00585 }
00586
00587 case SYNC_STATE_RENAME_FOLDER:
00588 {
00589 mSyncState = SYNC_STATE_CHECK_UIDVALIDITY;
00590
00591 QString newName = mAccount->renamedFolder( imapPath() );
00592 if ( !newName.isEmpty() ) {
00593 newState( mProgress, i18n("Renaming folder") );
00594 CachedImapJob *job = new CachedImapJob( newName, CachedImapJob::tRenameFolder, this );
00595 connect( job, SIGNAL( result(KMail::FolderJob *) ), this, SLOT( slotIncreaseProgress() ) );
00596 connect( job, SIGNAL( finished() ), this, SLOT( serverSyncInternal() ) );
00597 job->start();
00598 break;
00599 }
00600 }
00601
00602 case SYNC_STATE_CHECK_UIDVALIDITY:
00603 mSyncState = SYNC_STATE_CREATE_SUBFOLDERS;
00604 if( !noContent() ) {
00605 checkUidValidity();
00606 break;
00607 }
00608
00609
00610 case SYNC_STATE_CREATE_SUBFOLDERS:
00611 mSyncState = SYNC_STATE_PUT_MESSAGES;
00612 createNewFolders();
00613 break;
00614
00615 case SYNC_STATE_PUT_MESSAGES:
00616 mSyncState = SYNC_STATE_UPLOAD_FLAGS;
00617 if( !noContent() ) {
00618 uploadNewMessages();
00619 break;
00620 }
00621
00622 case SYNC_STATE_UPLOAD_FLAGS:
00623 mSyncState = SYNC_STATE_LIST_SUBFOLDERS;
00624 if( !noContent() ) {
00625
00626 if( uidMapDirty )
00627 reloadUidMap();
00628
00629
00630 if ( mUserRights <= 0 || ( mUserRights & KMail::ACLJobs::WriteFlags ) ) {
00631 if ( mStatusChangedLocally ) {
00632 uploadFlags();
00633 break;
00634 } else {
00635 kdDebug(5006) << "Skipping flags upload, folder unchanged: " << label() << endl;
00636 }
00637 }
00638 }
00639
00640 case SYNC_STATE_LIST_SUBFOLDERS:
00641 mSyncState = SYNC_STATE_LIST_SUBFOLDERS2;
00642 newState( mProgress, i18n("Retrieving folderlist"));
00643 if( !listDirectory() ) {
00644 mSyncState = SYNC_STATE_INITIAL;
00645 KMessageBox::error(0, i18n("Error while retrieving the folderlist"));
00646 }
00647 break;
00648
00649 case SYNC_STATE_LIST_SUBFOLDERS2:
00650 mSyncState = SYNC_STATE_DELETE_SUBFOLDERS;
00651 mProgress += 10;
00652 newState( mProgress, i18n("Retrieving subfolders"));
00653 listDirectory2();
00654 break;
00655
00656 case SYNC_STATE_DELETE_SUBFOLDERS:
00657 mSyncState = SYNC_STATE_LIST_MESSAGES;
00658 if( !foldersForDeletionOnServer.isEmpty() ) {
00659 newState( mProgress, i18n("Deleting folders from server"));
00660 CachedImapJob* job = new CachedImapJob( foldersForDeletionOnServer,
00661 CachedImapJob::tDeleteFolders, this );
00662 connect( job, SIGNAL( result(KMail::FolderJob *) ), this, SLOT( slotIncreaseProgress() ) );
00663 connect( job, SIGNAL( finished() ), this, SLOT( serverSyncInternal() ) );
00664 job->start();
00665 break;
00666 }
00667
00668
00669
00670
00671 case SYNC_STATE_LIST_MESSAGES:
00672 mSyncState = SYNC_STATE_DELETE_MESSAGES;
00673 if( !noContent() ) {
00674 newState( mProgress, i18n("Retrieving message list"));
00675 listMessages();
00676 break;
00677 }
00678
00679
00680 case SYNC_STATE_DELETE_MESSAGES:
00681 mSyncState = SYNC_STATE_EXPUNGE_MESSAGES;
00682 if( !noContent() ) {
00683 if( deleteMessages() ) {
00684
00685 } else {
00686
00687 newState( mProgress, i18n("No messages to delete..."));
00688 mSyncState = SYNC_STATE_GET_MESSAGES;
00689 serverSyncInternal();
00690 }
00691 break;
00692 }
00693
00694
00695 case SYNC_STATE_EXPUNGE_MESSAGES:
00696 mSyncState = SYNC_STATE_GET_MESSAGES;
00697 if( !noContent() ) {
00698 newState( mProgress, i18n("Expunging deleted messages"));
00699 CachedImapJob *job = new CachedImapJob( QString::null,
00700 CachedImapJob::tExpungeFolder, this );
00701 connect( job, SIGNAL( result(KMail::FolderJob *) ), this, SLOT( slotIncreaseProgress() ) );
00702 connect( job, SIGNAL( finished() ), this, SLOT( serverSyncInternal() ) );
00703 job->start();
00704 break;
00705 }
00706
00707
00708 case SYNC_STATE_GET_MESSAGES:
00709 mSyncState = SYNC_STATE_HANDLE_INBOX;
00710 if( !noContent() ) {
00711 if( !mMsgsForDownload.isEmpty() ) {
00712 newState( mProgress, i18n("Retrieving new messages"));
00713 CachedImapJob *job = new CachedImapJob( mMsgsForDownload,
00714 CachedImapJob::tGetMessage,
00715 this );
00716 connect( job, SIGNAL( progress(unsigned long, unsigned long) ),
00717 this, SLOT( slotProgress(unsigned long, unsigned long) ) );
00718 connect( job, SIGNAL( finished() ), this, SLOT( slotUpdateLastUid() ) );
00719 connect( job, SIGNAL( finished() ), this, SLOT( serverSyncInternal() ) );
00720 job->start();
00721 mMsgsForDownload.clear();
00722 break;
00723 } else {
00724 newState( mProgress, i18n("No new messages from server"));
00725
00726
00727
00728
00729
00730 slotUpdateLastUid();
00731 if( mLastUid == 0 && uidWriteTimer == -1 )
00732
00733 writeUidCache();
00734 }
00735 }
00736
00737
00738
00739 case SYNC_STATE_HANDLE_INBOX:
00740
00741 mProgress = 95;
00742
00743
00744 mSyncState = SYNC_STATE_SET_ACLS;
00745
00746 case SYNC_STATE_SET_ACLS:
00747 mSyncState = SYNC_STATE_GET_ACLS;
00748
00749 if( !noContent() && mAccount->hasACLSupport() ) {
00750 bool hasChangedACLs = false;
00751 ACLList::ConstIterator it = mACLList.begin();
00752 for ( ; it != mACLList.end() && !hasChangedACLs; ++it ) {
00753 hasChangedACLs = (*it).changed;
00754 }
00755 if ( hasChangedACLs ) {
00756 newState( mProgress, i18n("Setting permissions"));
00757 KURL url = mAccount->getUrl();
00758 url.setPath( imapPath() );
00759 KIO::Job* job = KMail::ACLJobs::multiSetACL( mAccount->slave(), url, mACLList );
00760 ImapAccountBase::jobData jd( url.url(), folder() );
00761 mAccount->insertJob(job, jd);
00762
00763 connect(job, SIGNAL(result(KIO::Job *)),
00764 SLOT(slotMultiSetACLResult(KIO::Job *)));
00765 connect(job, SIGNAL(aclChanged( const QString&, int )),
00766 SLOT(slotACLChanged( const QString&, int )) );
00767 break;
00768 }
00769 }
00770
00771 case SYNC_STATE_GET_ACLS:
00772
00773 mSyncState = SYNC_STATE_FIND_SUBFOLDERS;
00774
00775 if( !noContent() && mAccount->hasACLSupport() ) {
00776 newState( mProgress, i18n( "Retrieving permissions" ) );
00777 mAccount->getACL( folder(), mImapPath );
00778 connect( mAccount, SIGNAL(receivedACL( KMFolder*, KIO::Job*, const KMail::ACLList& )),
00779 this, SLOT(slotReceivedACL( KMFolder*, KIO::Job*, const KMail::ACLList& )) );
00780 break;
00781 }
00782
00783 case SYNC_STATE_FIND_SUBFOLDERS:
00784 {
00785 mProgress = 98;
00786 newState( mProgress, i18n("Updating cache file"));
00787
00788 mSyncState = SYNC_STATE_SYNC_SUBFOLDERS;
00789 mSubfoldersForSync.clear();
00790 mCurrentSubfolder = 0;
00791 if( folder() && folder()->child() ) {
00792 KMFolderNode *node = folder()->child()->first();
00793 while( node ) {
00794 if( !node->isDir() ) {
00795 KMFolderCachedImap* storage = static_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage());
00796
00797 if ( !storage->imapPath().isEmpty()
00798
00799 && !foldersForDeletionOnServer.contains( storage->imapPath() ) )
00800 mSubfoldersForSync << storage;
00801 }
00802 node = folder()->child()->next();
00803 }
00804 }
00805 }
00806
00807
00808 mProgress = 100;
00809 newState( mProgress, i18n("Synchronization done"));
00810
00811 if ( !mRecurse )
00812 mSubfoldersForSync.clear();
00813
00814
00815 case SYNC_STATE_SYNC_SUBFOLDERS:
00816 {
00817 if( mCurrentSubfolder ) {
00818 disconnect( mCurrentSubfolder, SIGNAL( folderComplete(KMFolderCachedImap*, bool) ),
00819 this, SLOT( slotSubFolderComplete(KMFolderCachedImap*, bool) ) );
00820 mCurrentSubfolder = 0;
00821 }
00822
00823 if( mSubfoldersForSync.isEmpty() ) {
00824 mSyncState = SYNC_STATE_INITIAL;
00825 mAccount->addUnreadMsgCount( this, countUnread() );
00826 close();
00827 emit folderComplete( this, TRUE );
00828 } else {
00829 mCurrentSubfolder = mSubfoldersForSync.front();
00830 mSubfoldersForSync.pop_front();
00831 connect( mCurrentSubfolder, SIGNAL( folderComplete(KMFolderCachedImap*, bool) ),
00832 this, SLOT( slotSubFolderComplete(KMFolderCachedImap*, bool) ) );
00833
00834
00835 assert( !mCurrentSubfolder->imapPath().isEmpty() );
00836 mCurrentSubfolder->setAccount( account() );
00837 mCurrentSubfolder->serverSync( mRecurse );
00838 }
00839 }
00840 break;
00841
00842 default:
00843 kdDebug(5006) << "KMFolderCachedImap::serverSyncInternal() WARNING: no such state "
00844 << mSyncState << endl;
00845 }
00846 }
00847
00848
00849
00850
00851 void KMFolderCachedImap::slotConnectionResult( int errorCode, const QString& errorMsg )
00852 {
00853 disconnect( mAccount, SIGNAL( connectionResult(int, const QString&) ),
00854 this, SLOT( slotConnectionResult(int, const QString&) ) );
00855 if ( !errorCode ) {
00856
00857 mSyncState = SYNC_STATE_GET_USERRIGHTS;
00858 mProgress += 5;
00859 serverSyncInternal();
00860 } else {
00861
00862 newState( mProgress, KIO::buildErrorString( errorCode, errorMsg ));
00863 emit folderComplete(this, FALSE);
00864 }
00865 }
00866
00867
00868 QValueList<unsigned long> KMFolderCachedImap::findNewMessages()
00869 {
00870 QValueList<unsigned long> result;
00871 for( int i = 0; i < count(); ++i ) {
00872 KMMsgBase *msg = getMsgBase( i );
00873 if( !msg ) continue;
00874 if ( msg->UID() == 0 )
00875 result.append( msg->getMsgSerNum() );
00876 }
00877 return result;
00878 }
00879
00880
00881 void KMFolderCachedImap::uploadNewMessages()
00882 {
00883 QValueList<unsigned long> newMsgs = findNewMessages();
00884 if( !newMsgs.isEmpty() ) {
00885
00886 newState( mProgress, i18n("Uploading messages to server"));
00887 CachedImapJob *job = new CachedImapJob( newMsgs, CachedImapJob::tPutMessage, this );
00888 connect( job, SIGNAL( progress( unsigned long, unsigned long) ),
00889 this, SLOT( slotPutProgress(unsigned long, unsigned long) ) );
00890 connect( job, SIGNAL( finished() ), this, SLOT( serverSyncInternal() ) );
00891 job->start();
00892 } else {
00893 newState( mProgress, i18n("No messages to upload to server"));
00894
00895 serverSyncInternal();
00896 }
00897 }
00898
00899
00900 void KMFolderCachedImap::slotPutProgress( unsigned long done, unsigned long total )
00901 {
00902
00903 int progressSpan = 10;
00904 newState( mProgress + (progressSpan * done) / total, QString::null );
00905 if ( done == total )
00906 mProgress += progressSpan;
00907 }
00908
00909
00910 void KMFolderCachedImap::uploadFlags()
00911 {
00912 if ( !uidMap.isEmpty() ) {
00913 mStatusFlagsJobs = 0;
00914 newState( mProgress, i18n("Uploading status of messages to server"));
00915
00916
00917 QMap< QString, QStringList > groups;
00918
00919 for( int i = 0; i < count(); ++i ) {
00920 KMMsgBase* msg = getMsgBase( i );
00921 if( !msg || msg->UID() == 0 )
00922
00923 continue;
00924
00925 QString flags = KMFolderImap::statusToFlags(msg->status());
00926
00927 QString uid;
00928 uid.setNum( msg->UID() );
00929 groups[flags].append(uid);
00930 }
00931 QMapIterator< QString, QStringList > dit;
00932 for( dit = groups.begin(); dit != groups.end(); ++dit ) {
00933 QCString flags = dit.key().latin1();
00934 QStringList sets = KMFolderImap::makeSets( (*dit), true );
00935 mStatusFlagsJobs += sets.count();
00936
00937 for( QStringList::Iterator slit = sets.begin(); slit != sets.end(); ++slit ) {
00938 QString imappath = imapPath() + ";UID=" + ( *slit );
00939 mAccount->setImapStatus(folder(), imappath, flags);
00940 }
00941 }
00942
00943
00944 if ( mStatusFlagsJobs ) {
00945 connect( mAccount, SIGNAL( imapStatusChanged(KMFolder*, const QString&, bool) ),
00946 this, SLOT( slotImapStatusChanged(KMFolder*, const QString&, bool) ) );
00947 return;
00948 }
00949 }
00950 newState( mProgress, i18n("No messages to upload to server"));
00951 serverSyncInternal();
00952 }
00953
00954 void KMFolderCachedImap::slotImapStatusChanged(KMFolder* folder, const QString&, bool cont)
00955 {
00956 if ( folder->storage() == this ) {
00957 --mStatusFlagsJobs;
00958 if ( mStatusFlagsJobs == 0 || !cont )
00959 disconnect( mAccount, SIGNAL( imapStatusChanged(KMFolder*, const QString&, bool) ),
00960 this, SLOT( slotImapStatusChanged(KMFolder*, const QString&, bool) ) );
00961 if ( mStatusFlagsJobs == 0 && cont ) {
00962 mProgress += 5;
00963 serverSyncInternal();
00964 }
00965 }
00966 }
00967
00968
00969 void KMFolderCachedImap::setStatus(QValueList<int>& ids, KMMsgStatus status, bool toggle)
00970 {
00971 KMFolderMaildir::setStatus(ids, status, toggle);
00972
00973 mStatusChangedLocally = true;
00974 }
00975
00976
00977 void KMFolderCachedImap::createNewFolders()
00978 {
00979 QValueList<KMFolderCachedImap*> newFolders = findNewFolders();
00980
00981 if( !newFolders.isEmpty() ) {
00982 newState( mProgress, i18n("Creating subfolders on server"));
00983 CachedImapJob *job = new CachedImapJob( newFolders, CachedImapJob::tAddSubfolders, this );
00984 connect( job, SIGNAL( result(KMail::FolderJob *) ), this, SLOT( slotIncreaseProgress() ) );
00985 connect( job, SIGNAL( finished() ), this, SLOT( serverSyncInternal() ) );
00986 job->start();
00987 } else {
00988 serverSyncInternal();
00989 }
00990 }
00991
00992 QValueList<KMFolderCachedImap*> KMFolderCachedImap::findNewFolders()
00993 {
00994 QValueList<KMFolderCachedImap*> newFolders;
00995 if( folder() && folder()->child() ) {
00996 KMFolderNode *node = folder()->child()->first();
00997 while( node ) {
00998 if( !node->isDir() ) {
00999 if( static_cast<KMFolder*>(node)->folderType() != KMFolderTypeCachedImap ) {
01000 kdError(5006) << "KMFolderCachedImap::findNewFolders(): ARGH!!! "
01001 << node->name() << " is not an IMAP folder\n";
01002 node = folder()->child()->next();
01003 assert(0);
01004 }
01005 KMFolderCachedImap* folder = static_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage());
01006 if( folder->imapPath().isEmpty() ) newFolders << folder;
01007 }
01008 node = folder()->child()->next();
01009 }
01010 }
01011 return newFolders;
01012 }
01013
01014 bool KMFolderCachedImap::deleteMessages()
01015 {
01016
01017 QPtrList<KMMessage> msgsForDeletion;
01018
01019
01020
01021
01022
01023 QMap<ulong,int>::const_iterator it = uidMap.constBegin();
01024 for( ; it != uidMap.end(); it++ ) {
01025 ulong uid ( it.key() );
01026 if( uid!=0 && !uidsOnServer.find( uid ) )
01027 msgsForDeletion.append( getMsg( *it ) );
01028 }
01029
01030 if( !msgsForDeletion.isEmpty() ) {
01031 removeMsg( msgsForDeletion );
01032 }
01033
01034
01035 if( !uidsForDeletionOnServer.isEmpty() ) {
01036 newState( mProgress, i18n("Deleting removed messages from server"));
01037 QStringList sets = KMFolderImap::makeSets( uidsForDeletionOnServer, true );
01038 uidsForDeletionOnServer.clear();
01039 kdDebug(5006) << "Deleting " << sets.count() << " sets of messages from server folder " << imapPath() << endl;
01040 CachedImapJob *job = new CachedImapJob( sets, CachedImapJob::tDeleteMessage, this );
01041 connect( job, SIGNAL( result(KMail::FolderJob *) ),
01042 this, SLOT( slotDeleteMessagesResult(KMail::FolderJob *) ) );
01043 job->start();
01044 return true;
01045 } else {
01046 return false;
01047 }
01048 }
01049
01050 void KMFolderCachedImap::slotDeleteMessagesResult( KMail::FolderJob* job )
01051 {
01052 if ( job->error() ) {
01053
01054 mSyncState = SYNC_STATE_GET_MESSAGES;
01055 }
01056 mProgress += 10;
01057 serverSyncInternal();
01058 }
01059
01060 void KMFolderCachedImap::checkUidValidity() {
01061
01062
01063 if( imapPath().isEmpty() || imapPath() == "/" )
01064
01065 serverSyncInternal();
01066 else {
01067 newState( mProgress, i18n("Checking folder validity"));
01068 CachedImapJob *job = new CachedImapJob( FolderJob::tCheckUidValidity, this );
01069 connect( job, SIGNAL( result( KMail::FolderJob* ) ),
01070 this, SLOT( slotCheckUidValidityResult( KMail::FolderJob* ) ) );
01071 job->start();
01072 }
01073 }
01074
01075 void KMFolderCachedImap::slotCheckUidValidityResult( KMail::FolderJob* job )
01076 {
01077 if ( job->error() ) {
01078
01079
01080 mSyncState = SYNC_STATE_HANDLE_INBOX;
01081 }
01082 mProgress += 5;
01083 serverSyncInternal();
01084 }
01085
01086
01087
01088 void KMFolderCachedImap::listMessages() {
01089 if( imapPath() == "/" ) {
01090
01091 serverSyncInternal();
01092 return;
01093 }
01094
01095 if( !mAccount->slave() ) {
01096 resetSyncState();
01097 emit folderComplete( this, false );
01098 return;
01099 }
01100 uidsOnServer.clear();
01101 uidsOnServer.resize( count() * 2 );
01102 uidsForDeletionOnServer.clear();
01103 mMsgsForDownload.clear();
01104 mUidsForDownload.clear();
01105
01106 CachedImapJob* job = new CachedImapJob( FolderJob::tListMessages, this );
01107 connect( job, SIGNAL( result(KMail::FolderJob *) ),
01108 this, SLOT( slotGetLastMessagesResult(KMail::FolderJob *) ) );
01109 job->start();
01110 }
01111
01112 void KMFolderCachedImap::slotGetLastMessagesResult(KMail::FolderJob *job)
01113 {
01114 getMessagesResult(job, true);
01115 }
01116
01117
01118 void KMFolderCachedImap::slotGetMessagesData(KIO::Job * job, const QByteArray & data)
01119 {
01120 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
01121 if ( it == mAccount->jobsEnd() ) {
01122 kdDebug(5006) << "could not find job!?!?!" << endl;
01123 serverSyncInternal();
01124 return;
01125 }
01126 (*it).cdata += QCString(data, data.size() + 1);
01127 int pos = (*it).cdata.find("\r\n--IMAPDIGEST");
01128 if (pos > 0) {
01129 int a = (*it).cdata.find("\r\nX-uidValidity:");
01130 if (a != -1) {
01131 int b = (*it).cdata.find("\r\n", a + 17);
01132 setUidValidity((*it).cdata.mid(a + 17, b - a - 17));
01133 }
01134 a = (*it).cdata.find("\r\nX-Access:");
01135 if (a != -1) {
01136 int b = (*it).cdata.find("\r\n", a + 12);
01137 QString access = (*it).cdata.mid(a + 12, b - a - 12);
01138 mReadOnly = access == "Read only";
01139 }
01140 (*it).cdata.remove(0, pos);
01141 }
01142 pos = (*it).cdata.find("\r\n--IMAPDIGEST", 1);
01143
01144 if ( uidsOnServer.size() == 0 )
01145 uidsOnServer.resize( KMail::nextPrime( 2000 ) );
01146 int flags;
01147 const int v = 42;
01148 while (pos >= 0) {
01149 KMMessage msg;
01150 msg.fromString((*it).cdata.mid(16, pos - 16));
01151 flags = msg.headerField("X-Flags").toInt();
01152 bool deleted = ( flags & 8 );
01153 ulong uid = msg.UID();
01154 if ( !deleted ) {
01155 if( uid != 0 ) {
01156 if ( uidsOnServer.count() == uidsOnServer.size() ) {
01157 uidsOnServer.resize( KMail::nextPrime( uidsOnServer.size() * 2 ) );
01158 kdDebug( 5006 ) << "Resizing to: " << uidsOnServer.size() << endl;
01159 }
01160 uidsOnServer.insert( uid, &v );
01161 }
01162 if ( uid <= lastUid() ) {
01163
01164
01165
01166
01167
01168
01169
01170
01171 KMMsgBase *existingMessage = findByUID(uid);
01172
01173
01174
01175 if( !existingMessage ) {
01176
01177 uidsForDeletionOnServer << uid;
01178 } else {
01179 if (!mReadOnly) {
01180
01181 KMFolderImap::flagsToStatus( existingMessage, flags );
01182 }
01183 }
01184
01185 } else {
01186
01187
01188 if ( !uidMap.contains( uid ) ) {
01189 ulong size = msg.headerField("X-Length").toULong();
01190 mMsgsForDownload << KMail::CachedImapJob::MsgForDownload(uid, flags, size);
01191 if( imapPath() == "/INBOX/" )
01192 mUidsForDownload << uid;
01193 }
01194
01195 if ( uid > mTentativeHighestUid )
01196 mTentativeHighestUid = uid;
01197 }
01198 }
01199 (*it).cdata.remove(0, pos);
01200 (*it).done++;
01201 pos = (*it).cdata.find("\r\n--IMAPDIGEST", 1);
01202 }
01203 }
01204
01205 void KMFolderCachedImap::getMessagesResult( KMail::FolderJob *job, bool lastSet )
01206 {
01207 mProgress += 10;
01208 if( job->error() ) {
01209 mContentState = imapNoInformation;
01210 } else {
01211 if( lastSet ) {
01212 mContentState = imapFinished;
01213 mStatusChangedLocally = false;
01214 }
01215 }
01216 serverSyncInternal();
01217 }
01218
01219 void KMFolderCachedImap::slotProgress(unsigned long done, unsigned long total)
01220 {
01221 int progressSpan = 100 - 5 - mProgress;
01222
01223
01224
01225 newState( mProgress + (progressSpan * done) / total, QString::null );
01226 }
01227
01228
01229 void KMFolderCachedImap::setAccount(KMAcctCachedImap *aAccount)
01230 {
01231 assert( aAccount->isA("KMAcctCachedImap") );
01232 mAccount = aAccount;
01233 if( imapPath()=="/" ) aAccount->setFolder( folder() );
01234
01235
01236 QString newName = mAccount->renamedFolder( imapPath() );
01237 if ( !newName.isEmpty() )
01238 folder()->setLabel( newName );
01239
01240 if( !folder() || !folder()->child() || !folder()->child()->count() ) return;
01241 for( KMFolderNode* node = folder()->child()->first(); node;
01242 node = folder()->child()->next() )
01243 if (!node->isDir())
01244 static_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage())->setAccount(aAccount);
01245 }
01246
01247
01248
01249
01250 bool KMFolderCachedImap::listDirectory(bool secondStep)
01251 {
01252 mSubfolderState = imapInProgress;
01253 if( !mAccount->slave() ) {
01254 resetSyncState();
01255 emit folderComplete( this, false );
01256 return false;
01257 }
01258
01259 if ( this == mAccount->rootFolder() )
01260 mAccount->setHasInbox( false );
01261
01262
01263 ImapAccountBase::ListType type = ImapAccountBase::List;
01264 if ( mAccount->onlySubscribedFolders() )
01265 type = ImapAccountBase::ListSubscribed;
01266 ListJob* job = new ListJob( this, mAccount, type, secondStep,
01267 false, mAccount->hasInbox() );
01268 connect( job, SIGNAL(receivedFolders(const QStringList&, const QStringList&,
01269 const QStringList&, const QStringList&, const ImapAccountBase::jobData&)),
01270 this, SLOT(slotListResult(const QStringList&, const QStringList&,
01271 const QStringList&, const QStringList&, const ImapAccountBase::jobData&)));
01272 job->start();
01273
01274 return true;
01275 }
01276
01277 void KMFolderCachedImap::slotListResult( const QStringList& folderNames,
01278 const QStringList& folderPaths,
01279 const QStringList& folderMimeTypes,
01280 const QStringList& folderAttributes,
01281 const ImapAccountBase::jobData& jobData )
01282 {
01283
01284 mSubfolderNames = folderNames;
01285 mSubfolderPaths = folderPaths;
01286 mSubfolderMimeTypes = folderMimeTypes;
01287 mSubfolderAttributes = folderAttributes;
01288
01289 mSubfolderState = imapFinished;
01290 bool it_inboxOnly = jobData.inboxOnly;
01291
01292 mCreateInbox = jobData.createInbox;
01293
01294 if (it_inboxOnly) {
01295
01296 listDirectory(TRUE);
01297 return;
01298 }
01299
01300 if ( folder()->isSystemFolder() && mImapPath == "/INBOX/"
01301 && mAccount->prefix() == "/INBOX/" )
01302 {
01303
01304 mCreateInbox = false;
01305 mSubfolderNames.clear();
01306 }
01307 folder()->createChildFolder();
01308
01309 KMFolderNode *node = folder()->child()->first();
01310 QPtrList<KMFolder> toRemove;
01311 while (node) {
01312 if (!node->isDir() ) {
01313 KMFolderCachedImap *f = static_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage());
01314 if ( mSubfolderNames.findIndex(node->name()) == -1 &&
01315 (node->name().upper() != "INBOX" || !mCreateInbox) )
01316 {
01317
01318 if( !f->imapPath().isEmpty() ) {
01319
01320
01321 toRemove.append( f->folder() );
01322 kdDebug(5006) << node->name() << " isn't on the server. It has an imapPath -> delete it locally" << endl;
01323 } else {
01324 kdDebug(5006) << node->name() << " isn't on the server, but has no imapPath. ERROR - why didn't createNewFolders create it?" << endl;
01325 }
01326 } else {
01327
01328 }
01329 } else {
01330
01331 }
01332 node = folder()->child()->next();
01333 }
01334
01335 for ( KMFolder* doomed=toRemove.first(); doomed; doomed = toRemove.next() )
01336 kmkernel->dimapFolderMgr()->remove( doomed );
01337
01338 mProgress += 5;
01339 serverSyncInternal();
01340 }
01341
01342
01343 void KMFolderCachedImap::listDirectory2() {
01344 foldersForDeletionOnServer.clear();
01345 QString path = folder()->path();
01346 KMFolderCachedImap *f = 0;
01347 kmkernel->dimapFolderMgr()->quiet(true);
01348
01349 if (mCreateInbox)
01350 {
01351 KMFolderNode *node;
01352
01353 for (node = folder()->child()->first(); node; node = folder()->child()->next())
01354 if (!node->isDir() && node->name() == "INBOX") break;
01355 if (node)
01356 f = static_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage());
01357 else {
01358 KMFolder* newFolder = folder()->child()->createFolder("INBOX", true, KMFolderTypeCachedImap);
01359 if (newFolder)
01360 f = static_cast<KMFolderCachedImap*>(newFolder->storage());
01361 }
01362 f->setAccount(mAccount);
01363 f->setImapPath("/INBOX/");
01364 f->folder()->setLabel(i18n("inbox"));
01365 if (!node) {
01366 f->close();
01367 kmkernel->dimapFolderMgr()->contentsChanged();
01368 }
01369
01370 mAccount->setHasInbox( true );
01371 }
01372
01373
01374 for (uint i = 0; i < mSubfolderNames.count(); i++) {
01375
01376 if (mSubfolderNames[i].upper() == "INBOX" &&
01377 mSubfolderPaths[i] == "/INBOX/" &&
01378 mAccount->hasInbox())
01379 continue;
01380
01381
01382 KMFolderNode *node;
01383 for (node = folder()->child()->first(); node;
01384 node = folder()->child()->next())
01385 if (!node->isDir() && node->name() == mSubfolderNames[i]) break;
01386
01387 if (!node) {
01388
01389
01390 QString subfolderPath = mSubfolderPaths[i];
01391
01392
01393
01394 bool locallyDeleted = mAccount->isDeletedFolder( subfolderPath );
01395
01396
01397
01398 if ( !locallyDeleted && mAccount->isPreviouslyDeletedFolder( subfolderPath ) ) {
01399 locallyDeleted = KMessageBox::warningYesNo(
01400 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] ) ) == KMessageBox::Yes;
01401 }
01402
01403 if ( locallyDeleted ) {
01404 kdDebug(5006) << subfolderPath << " was deleted locally => delete on server." << endl;
01405 foldersForDeletionOnServer << subfolderPath;
01406 } else {
01407 kdDebug(5006) << subfolderPath << " is a new folder on the server => create local cache" << endl;
01408 KMFolder* newFolder = folder()->child()->createFolder(mSubfolderNames[i], false, KMFolderTypeCachedImap);
01409 if (newFolder)
01410 f = static_cast<KMFolderCachedImap*>(newFolder->storage());
01411 if (f) {
01412 f->close();
01413 f->setAccount(mAccount);
01414 kmkernel->dimapFolderMgr()->contentsChanged();
01415 } else {
01416 kdDebug(5006) << "can't create folder " << mSubfolderNames[i] <<endl;
01417 }
01418 }
01419 } else {
01420 if( static_cast<KMFolder*>(node)->folderType() == KMFolderTypeCachedImap )
01421 f = static_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage());
01422 }
01423
01424 if( f ) {
01425
01426
01427
01428 f->setAccount(mAccount);
01429 f->setNoContent(mSubfolderMimeTypes[i] == "inode/directory");
01430 f->setNoChildren(mSubfolderMimeTypes[i] == "message/digest");
01431 f->setImapPath(mSubfolderPaths[i]);
01432 }
01433 }
01434 kmkernel->dimapFolderMgr()->quiet(false);
01435 emit listComplete(this);
01436 serverSyncInternal();
01437 }
01438
01439 void KMFolderCachedImap::slotSubFolderComplete(KMFolderCachedImap* sub, bool success)
01440 {
01441 Q_UNUSED(sub);
01442
01443 if ( success ) {
01444 serverSyncInternal();
01445 }
01446 else
01447 {
01448
01449 if ( mCurrentSubfolder ) {
01450 Q_ASSERT( sub == mCurrentSubfolder );
01451 disconnect( mCurrentSubfolder, SIGNAL( folderComplete(KMFolderCachedImap*, bool) ),
01452 this, SLOT( slotSubFolderComplete(KMFolderCachedImap*, bool) ) );
01453 mCurrentSubfolder = 0;
01454 }
01455
01456 mSubfoldersForSync.clear();
01457 mSyncState = SYNC_STATE_INITIAL;
01458 close();
01459 emit folderComplete( this, false );
01460 }
01461 }
01462
01463 void KMFolderCachedImap::slotSimpleData(KIO::Job * job, const QByteArray & data)
01464 {
01465 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
01466 if (it == mAccount->jobsEnd()) return;
01467 QBuffer buff((*it).data);
01468 buff.open(IO_WriteOnly | IO_Append);
01469 buff.writeBlock(data.data(), data.size());
01470 buff.close();
01471 }
01472
01473
01474 FolderJob*
01475 KMFolderCachedImap::doCreateJob( KMMessage *msg, FolderJob::JobType jt, KMFolder *folder,
01476 QString, const AttachmentStrategy* ) const
01477 {
01478 QPtrList<KMMessage> msgList;
01479 msgList.append( msg );
01480 CachedImapJob *job = new CachedImapJob( msgList, jt, folder? static_cast<KMFolderCachedImap*>( folder->storage() ):0 );
01481 job->setParentFolder( this );
01482 return job;
01483 }
01484
01485 FolderJob*
01486 KMFolderCachedImap::doCreateJob( QPtrList<KMMessage>& msgList, const QString& sets,
01487 FolderJob::JobType jt, KMFolder *folder ) const
01488 {
01489
01490 Q_UNUSED( sets );
01491 CachedImapJob *job = new CachedImapJob( msgList, jt, folder? static_cast<KMFolderCachedImap*>( folder->storage() ):0 );
01492 job->setParentFolder( this );
01493 return job;
01494 }
01495
01496 void
01497 KMFolderCachedImap::setUserRights( unsigned int userRights )
01498 {
01499 mUserRights = userRights;
01500 }
01501
01502 void
01503 KMFolderCachedImap::slotReceivedUserRights( KMFolder* folder )
01504 {
01505 if ( folder->storage() == this ) {
01506 disconnect( mAccount, SIGNAL( receivedUserRights( KMFolder* ) ),
01507 this, SLOT( slotReceivedUserRights( KMFolder* ) ) );
01508 if ( mUserRights == 0 )
01509 mUserRights = -1;
01510 else
01511 mReadOnly = ( mUserRights & KMail::ACLJobs::Insert ) == 0;
01512 mProgress += 5;
01513 serverSyncInternal();
01514 }
01515 }
01516
01517 void
01518 KMFolderCachedImap::slotReceivedACL( KMFolder* folder, KIO::Job*, const KMail::ACLList& aclList )
01519 {
01520 if ( folder->storage() == this ) {
01521 disconnect( mAccount, SIGNAL(receivedACL( KMFolder*, KIO::Job*, const KMail::ACLList& )),
01522 this, SLOT(slotReceivedACL( KMFolder*, KIO::Job*, const KMail::ACLList& )) );
01523 mACLList = aclList;
01524 serverSyncInternal();
01525 }
01526 }
01527
01528 void
01529 KMFolderCachedImap::setACLList( const ACLList& arr )
01530 {
01531 mACLList = arr;
01532 }
01533
01534 void
01535 KMFolderCachedImap::slotMultiSetACLResult(KIO::Job *job)
01536 {
01537 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
01538 if ( it == mAccount->jobsEnd() ) return;
01539 if ( (*it).parent != folder() ) return;
01540
01541 if ( job->error() )
01542
01543
01544 job->showErrorDialog();
01545
01546 if (mAccount->slave()) mAccount->removeJob(job);
01547 serverSyncInternal();
01548 }
01549
01550 void
01551 KMFolderCachedImap::slotACLChanged( const QString& userId, int permissions )
01552 {
01553
01554
01555 for( ACLList::Iterator it = mACLList.begin(); it != mACLList.end(); ++it ) {
01556 if ( (*it).userId == userId && (*it).permissions == permissions ) {
01557 if ( permissions == -1 )
01558 mACLList.erase( it );
01559 else
01560 (*it).changed = false;
01561 return;
01562 }
01563 }
01564 }
01565
01566
01567 void KMFolderCachedImap::resetSyncState()
01568 {
01569 mSubfoldersForSync.clear();
01570 mSyncState = SYNC_STATE_INITIAL;
01571 close();
01572
01573 ProgressItem *progressItem = mAccount->mailCheckProgressItem();
01574 QString str = i18n("Aborted");
01575 if (progressItem)
01576 progressItem->setStatus( str );
01577 emit statusMsg( str );
01578 }
01579
01580 void KMFolderCachedImap::slotIncreaseProgress()
01581 {
01582 mProgress += 5;
01583 }
01584
01585 void KMFolderCachedImap::newState( int progress, const QString& syncStatus )
01586 {
01587
01588 ProgressItem *progressItem = mAccount->mailCheckProgressItem();
01589 if( progressItem )
01590 progressItem->setCompletedItems( progress );
01591 if ( !syncStatus.isEmpty() ) {
01592 QString str;
01593
01594 if ( mAccount->imapFolder() == this )
01595 str = syncStatus;
01596 else
01597 str = QString( "%1: %2" ).arg( label() ).arg( syncStatus );
01598 if( progressItem )
01599 progressItem->setStatus( str );
01600 emit statusMsg( str );
01601 }
01602 if( progressItem )
01603 progressItem->updateProgress();
01604 }
01605
01606 void KMFolderCachedImap::setSubfolderState( imapState state )
01607 {
01608 mSubfolderState = state;
01609 if ( state == imapNoInformation && folder()->child() )
01610 {
01611
01612 KMFolderNode* node;
01613 QPtrListIterator<KMFolderNode> it( *folder()->child() );
01614 for ( ; (node = it.current()); )
01615 {
01616 ++it;
01617 if (node->isDir()) continue;
01618 KMFolder *folder = static_cast<KMFolder*>(node);
01619 static_cast<KMFolderCachedImap*>(folder->storage())->setSubfolderState( state );
01620 }
01621 }
01622 }
01623
01624 void KMFolderCachedImap::setImapPath(const QString &path)
01625 {
01626 mImapPath = path;
01627 }
01628
01629 void KMFolderCachedImap::setContentsType( KMail::FolderContentsType type )
01630 {
01631 if ( type != mContentsType ) {
01632 FolderStorage::setContentsType( type );
01633 mContentsTypeChanged = true;
01634 }
01635 }
01636
01637 void KMFolderCachedImap::slotUpdateLastUid()
01638 {
01639 if( mTentativeHighestUid != 0 )
01640 setLastUid( mTentativeHighestUid );
01641 mTentativeHighestUid = 0;
01642 }
01643
01644 #include "kmfoldercachedimap.moc"