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 ), mReadOnly( false ), 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 ProgressItem *progressItem = mAccount->mailCheckProgressItem();
00543 if ( progressItem ) {
00544 progressItem->reset();
00545 progressItem->setTotalItems( 100 );
00546 }
00547 mProgress = 0;
00548
00549 #if 0
00550 if( mHoldSyncs ) {
00551
00552 account()->mailCheckProgressItem()->setProgress( 100 );
00553 mProgress = 100;
00554 newState( mProgress, i18n("Synchronization skipped"));
00555 mSyncState = SYNC_STATE_INITIAL;
00556 emit folderComplete( this, true );
00557 return;
00558 }
00559 #endif
00560 mTentativeHighestUid = 0;
00561
00562 serverSyncInternal();
00563 }
00564
00565 QString KMFolderCachedImap::state2String( int state ) const
00566 {
00567 switch( state ) {
00568 case SYNC_STATE_INITIAL: return "SYNC_STATE_INITIAL";
00569 case SYNC_STATE_GET_USERRIGHTS: return "SYNC_STATE_GET_USERRIGHTS";
00570 case SYNC_STATE_PUT_MESSAGES: return "SYNC_STATE_PUT_MESSAGES";
00571 case SYNC_STATE_UPLOAD_FLAGS: return "SYNC_STATE_UPLOAD_FLAGS";
00572 case SYNC_STATE_CREATE_SUBFOLDERS: return "SYNC_STATE_CREATE_SUBFOLDERS";
00573 case SYNC_STATE_LIST_SUBFOLDERS: return "SYNC_STATE_LIST_SUBFOLDERS";
00574 case SYNC_STATE_LIST_NAMESPACES: return "SYNC_STATE_LIST_NAMESPACES";
00575 case SYNC_STATE_LIST_SUBFOLDERS2: return "SYNC_STATE_LIST_SUBFOLDERS2";
00576 case SYNC_STATE_DELETE_SUBFOLDERS: return "SYNC_STATE_DELETE_SUBFOLDERS";
00577 case SYNC_STATE_LIST_MESSAGES: return "SYNC_STATE_LIST_MESSAGES";
00578 case SYNC_STATE_DELETE_MESSAGES: return "SYNC_STATE_DELETE_MESSAGES";
00579 case SYNC_STATE_GET_MESSAGES: return "SYNC_STATE_GET_MESSAGES";
00580 case SYNC_STATE_EXPUNGE_MESSAGES: return "SYNC_STATE_EXPUNGE_MESSAGES";
00581 case SYNC_STATE_HANDLE_INBOX: return "SYNC_STATE_HANDLE_INBOX";
00582 case SYNC_STATE_TEST_ANNOTATIONS: return "SYNC_STATE_TEST_ANNOTATIONS";
00583 case SYNC_STATE_GET_ANNOTATIONS: return "SYNC_STATE_GET_ANNOTATIONS";
00584 case SYNC_STATE_SET_ANNOTATIONS: return "SYNC_STATE_SET_ANNOTATIONS";
00585 case SYNC_STATE_GET_ACLS: return "SYNC_STATE_GET_ACLS";
00586 case SYNC_STATE_SET_ACLS: return "SYNC_STATE_SET_ACLS";
00587 case SYNC_STATE_FIND_SUBFOLDERS: return "SYNC_STATE_FIND_SUBFOLDERS";
00588 case SYNC_STATE_SYNC_SUBFOLDERS: return "SYNC_STATE_SYNC_SUBFOLDERS";
00589 case SYNC_STATE_RENAME_FOLDER: return "SYNC_STATE_RENAME_FOLDER";
00590 case SYNC_STATE_CHECK_UIDVALIDITY: return "SYNC_STATE_CHECK_UIDVALIDITY";
00591 default: return "Unknown state";
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
00624
00625
00626 void KMFolderCachedImap::serverSyncInternal()
00627 {
00628
00629
00630
00631 if( kmkernel->mailCheckAborted() ) {
00632 resetSyncState();
00633 emit folderComplete( this, false );
00634 return;
00635 }
00636
00637
00638 switch( mSyncState ) {
00639 case SYNC_STATE_INITIAL:
00640 {
00641 mProgress = 0;
00642 foldersForDeletionOnServer.clear();
00643 newState( mProgress, i18n("Synchronizing"));
00644
00645 open();
00646 if ( !noContent() )
00647 mAccount->addLastUnreadMsgCount( this, countUnread() );
00648
00649
00650 ImapAccountBase::ConnectionState cs = mAccount->makeConnection();
00651 if ( cs == ImapAccountBase::Error ) {
00652
00653
00654
00655 newState( mProgress, i18n( "Error connecting to server %1" ).arg( mAccount->host() ) );
00656 close();
00657 emit folderComplete(this, false);
00658 break;
00659 } else if ( cs == ImapAccountBase::Connecting ) {
00660 mAccount->setAnnotationCheckPassed( false );
00661
00662 newState( mProgress, i18n("Connecting to %1").arg( mAccount->host() ) );
00663
00664 connect( mAccount, SIGNAL( connectionResult(int, const QString&) ),
00665 this, SLOT( slotConnectionResult(int, const QString&) ) );
00666 break;
00667 } else {
00668
00669
00670 mSyncState = SYNC_STATE_GET_USERRIGHTS;
00671
00672 }
00673 }
00674
00675
00676 case SYNC_STATE_GET_USERRIGHTS:
00677
00678
00679 mSyncState = SYNC_STATE_RENAME_FOLDER;
00680
00681 if( !noContent() && mAccount->hasACLSupport() ) {
00682
00683 newState( mProgress, i18n("Checking permissions"));
00684 connect( mAccount, SIGNAL( receivedUserRights( KMFolder* ) ),
00685 this, SLOT( slotReceivedUserRights( KMFolder* ) ) );
00686 mAccount->getUserRights( folder(), imapPath() );
00687 break;
00688 }
00689
00690 case SYNC_STATE_RENAME_FOLDER:
00691 {
00692 mSyncState = SYNC_STATE_CHECK_UIDVALIDITY;
00693
00694 bool isResourceFolder = kmkernel->iCalIface().isStandardResourceFolder( folder() );
00695 QString newName = mAccount->renamedFolder( imapPath() );
00696 if ( !newName.isEmpty() && !folder()->isSystemFolder() && !isResourceFolder ) {
00697 newState( mProgress, i18n("Renaming folder") );
00698 CachedImapJob *job = new CachedImapJob( newName, CachedImapJob::tRenameFolder, this );
00699 connect( job, SIGNAL( result(KMail::FolderJob *) ), this, SLOT( slotIncreaseProgress() ) );
00700 connect( job, SIGNAL( finished() ), this, SLOT( serverSyncInternal() ) );
00701 job->start();
00702 break;
00703 }
00704 }
00705
00706 case SYNC_STATE_CHECK_UIDVALIDITY:
00707 mSyncState = SYNC_STATE_CREATE_SUBFOLDERS;
00708 if( !noContent() ) {
00709 checkUidValidity();
00710 break;
00711 }
00712
00713
00714 case SYNC_STATE_CREATE_SUBFOLDERS:
00715 mSyncState = SYNC_STATE_PUT_MESSAGES;
00716 createNewFolders();
00717 break;
00718
00719 case SYNC_STATE_PUT_MESSAGES:
00720 mSyncState = SYNC_STATE_UPLOAD_FLAGS;
00721 if( !noContent() ) {
00722 uploadNewMessages();
00723 break;
00724 }
00725
00726 case SYNC_STATE_UPLOAD_FLAGS:
00727 mSyncState = SYNC_STATE_LIST_NAMESPACES;
00728 if( !noContent() ) {
00729
00730 if( uidMapDirty )
00731 reloadUidMap();
00732
00733
00734 if ( mUserRights <= 0 || ( mUserRights & KMail::ACLJobs::WriteFlags ) ) {
00735 if ( mStatusChangedLocally ) {
00736 uploadFlags();
00737 break;
00738 } else {
00739
00740 }
00741 }
00742 }
00743
00744
00745 case SYNC_STATE_LIST_NAMESPACES:
00746 if ( this == mAccount->rootFolder() ) {
00747 listNamespaces();
00748 break;
00749 }
00750 mSyncState = SYNC_STATE_LIST_SUBFOLDERS;
00751
00752
00753 case SYNC_STATE_LIST_SUBFOLDERS:
00754 newState( mProgress, i18n("Retrieving folderlist"));
00755 mSyncState = SYNC_STATE_LIST_SUBFOLDERS2;
00756 if( !listDirectory() ) {
00757 mSyncState = SYNC_STATE_INITIAL;
00758 KMessageBox::error(0, i18n("Error while retrieving the folderlist"));
00759 }
00760 break;
00761
00762 case SYNC_STATE_LIST_SUBFOLDERS2:
00763 mSyncState = SYNC_STATE_DELETE_SUBFOLDERS;
00764 mProgress += 10;
00765 newState( mProgress, i18n("Retrieving subfolders"));
00766 listDirectory2();
00767 break;
00768
00769 case SYNC_STATE_DELETE_SUBFOLDERS:
00770 mSyncState = SYNC_STATE_LIST_MESSAGES;
00771 if( !foldersForDeletionOnServer.isEmpty() ) {
00772 newState( mProgress, i18n("Deleting folders from server"));
00773 CachedImapJob* job = new CachedImapJob( foldersForDeletionOnServer,
00774 CachedImapJob::tDeleteFolders, this );
00775 connect( job, SIGNAL( result(KMail::FolderJob *) ), this, SLOT( slotIncreaseProgress() ) );
00776 connect( job, SIGNAL( finished() ), this, SLOT( slotFolderDeletionOnServerFinished() ) );
00777 job->start();
00778 break;
00779 }
00780
00781
00782
00783
00784 case SYNC_STATE_LIST_MESSAGES:
00785 mSyncState = SYNC_STATE_DELETE_MESSAGES;
00786 if( !noContent() ) {
00787 newState( mProgress, i18n("Retrieving message list"));
00788 listMessages();
00789 break;
00790 }
00791
00792
00793 case SYNC_STATE_DELETE_MESSAGES:
00794 mSyncState = SYNC_STATE_EXPUNGE_MESSAGES;
00795 if( !noContent() ) {
00796 if( deleteMessages() ) {
00797
00798 } else {
00799
00800 newState( mProgress, i18n("No messages to delete..."));
00801 mSyncState = SYNC_STATE_GET_MESSAGES;
00802 serverSyncInternal();
00803 }
00804 break;
00805 }
00806
00807
00808 case SYNC_STATE_EXPUNGE_MESSAGES:
00809 mSyncState = SYNC_STATE_GET_MESSAGES;
00810 if( !noContent() ) {
00811 newState( mProgress, i18n("Expunging deleted messages"));
00812 CachedImapJob *job = new CachedImapJob( QString::null,
00813 CachedImapJob::tExpungeFolder, this );
00814 connect( job, SIGNAL( result(KMail::FolderJob *) ), this, SLOT( slotIncreaseProgress() ) );
00815 connect( job, SIGNAL( finished() ), this, SLOT( serverSyncInternal() ) );
00816 job->start();
00817 break;
00818 }
00819
00820
00821 case SYNC_STATE_GET_MESSAGES:
00822 mSyncState = SYNC_STATE_HANDLE_INBOX;
00823 if( !noContent() ) {
00824 if( !mMsgsForDownload.isEmpty() ) {
00825 newState( mProgress, i18n("Retrieving new messages"));
00826 CachedImapJob *job = new CachedImapJob( mMsgsForDownload,
00827 CachedImapJob::tGetMessage,
00828 this );
00829 connect( job, SIGNAL( progress(unsigned long, unsigned long) ),
00830 this, SLOT( slotProgress(unsigned long, unsigned long) ) );
00831 connect( job, SIGNAL( finished() ), this, SLOT( slotUpdateLastUid() ) );
00832 connect( job, SIGNAL( finished() ), this, SLOT( serverSyncInternal() ) );
00833 job->start();
00834 mMsgsForDownload.clear();
00835 break;
00836 } else {
00837 newState( mProgress, i18n("No new messages from server"));
00838
00839
00840
00841
00842
00843 slotUpdateLastUid();
00844 if( mLastUid == 0 && uidWriteTimer == -1 )
00845
00846 writeUidCache();
00847 }
00848 }
00849
00850
00851
00852 case SYNC_STATE_HANDLE_INBOX:
00853
00854 mProgress = 95;
00855 mSyncState = SYNC_STATE_TEST_ANNOTATIONS;
00856
00857 #define KOLAB_FOLDERTEST "/vendor/kolab/folder-test"
00858 case SYNC_STATE_TEST_ANNOTATIONS:
00859 mSyncState = SYNC_STATE_GET_ANNOTATIONS;
00860
00861 if( !mAccount->annotationCheckPassed() &&
00862 ( mUserRights <= 0 || ( mUserRights & ACLJobs::Administer ) )
00863 && !imapPath().isEmpty() && imapPath() != "/" ) {
00864 kdDebug(5006) << "Setting test attribute on folder: "<< folder()->prettyURL() << endl;
00865 newState( mProgress, i18n("Checking annotation support"));
00866
00867 KURL url = mAccount->getUrl();
00868 url.setPath( imapPath() );
00869 KMail::AnnotationList annotations;
00870
00871 KMail::AnnotationAttribute attr( KOLAB_FOLDERTEST, "value.shared", "true" );
00872 annotations.append( attr );
00873
00874 kdDebug(5006) << "Setting test attribute to "<< url << endl;
00875 KIO::Job* job = AnnotationJobs::multiSetAnnotation( mAccount->slave(),
00876 url, annotations );
00877 ImapAccountBase::jobData jd( url.url(), folder() );
00878 jd.cancellable = true;
00879 mAccount->insertJob(job, jd);
00880 connect(job, SIGNAL(result(KIO::Job *)),
00881 SLOT(slotTestAnnotationResult(KIO::Job *)));
00882 break;
00883 }
00884
00885 case SYNC_STATE_GET_ANNOTATIONS: {
00886 #define KOLAB_FOLDERTYPE "/vendor/kolab/folder-type"
00887 #define KOLAB_INCIDENCESFOR "/vendor/kolab/incidences-for"
00888
00889 mSyncState = SYNC_STATE_SET_ANNOTATIONS;
00890
00891 bool needToGetInitialAnnotations = false;
00892 if ( !noContent() ) {
00893
00894 if ( mAnnotationFolderType == "FROMSERVER" ) {
00895 needToGetInitialAnnotations = true;
00896 mAnnotationFolderType = QString::null;
00897 } else {
00898 updateAnnotationFolderType();
00899 }
00900 }
00901
00902
00903
00904 if ( !noContent() && mAccount->hasAnnotationSupport() &&
00905 ( kmkernel->iCalIface().isEnabled() || needToGetInitialAnnotations ) ) {
00906 QStringList annotations;
00907 if ( !mAnnotationFolderTypeChanged || mAnnotationFolderType.isEmpty() )
00908 annotations << KOLAB_FOLDERTYPE;
00909 if ( !mIncidencesForChanged )
00910 annotations << KOLAB_INCIDENCESFOR;
00911 if ( !annotations.isEmpty() ) {
00912 newState( mProgress, i18n("Retrieving annotations"));
00913 KURL url = mAccount->getUrl();
00914 url.setPath( imapPath() );
00915 AnnotationJobs::MultiGetAnnotationJob* job =
00916 AnnotationJobs::multiGetAnnotation( mAccount->slave(), url, annotations );
00917 ImapAccountBase::jobData jd( url.url(), folder() );
00918 jd.cancellable = true;
00919 mAccount->insertJob(job, jd);
00920
00921 connect( job, SIGNAL(annotationResult(const QString&, const QString&, bool)),
00922 SLOT(slotAnnotationResult(const QString&, const QString&, bool)) );
00923 connect( job, SIGNAL(result(KIO::Job *)),
00924 SLOT(slotGetAnnotationResult(KIO::Job *)) );
00925 break;
00926 }
00927 }
00928 }
00929 case SYNC_STATE_SET_ANNOTATIONS:
00930
00931 mSyncState = SYNC_STATE_SET_ACLS;
00932 if ( !noContent() && mAccount->hasAnnotationSupport() &&
00933 ( mUserRights <= 0 || ( mUserRights & ACLJobs::Administer ) ) ) {
00934 newState( mProgress, i18n("Setting annotations"));
00935 KURL url = mAccount->getUrl();
00936 url.setPath( imapPath() );
00937 KMail::AnnotationList annotations;
00938 if ( mAnnotationFolderTypeChanged && !mAnnotationFolderType.isEmpty() ) {
00939 KMail::AnnotationAttribute attr( KOLAB_FOLDERTYPE, "value.shared", mAnnotationFolderType );
00940 annotations.append( attr );
00941 kdDebug(5006) << "Setting folder-type annotation for " << label() << " to " << mAnnotationFolderType << endl;
00942 }
00943 if ( mIncidencesForChanged ) {
00944 const QString val = incidencesForToString( mIncidencesFor );
00945 KMail::AnnotationAttribute attr( KOLAB_INCIDENCESFOR, "value.shared", val );
00946 annotations.append( attr );
00947 kdDebug(5006) << "Setting incidences-for annotation for " << label() << " to " << val << endl;
00948 }
00949 if ( !annotations.isEmpty() ) {
00950 KIO::Job* job =
00951 AnnotationJobs::multiSetAnnotation( mAccount->slave(), url, annotations );
00952 ImapAccountBase::jobData jd( url.url(), folder() );
00953 jd.cancellable = true;
00954 mAccount->insertJob(job, jd);
00955
00956 connect(job, SIGNAL(annotationChanged( const QString&, const QString&, const QString& ) ),
00957 SLOT( slotAnnotationChanged( const QString&, const QString&, const QString& ) ));
00958 connect(job, SIGNAL(result(KIO::Job *)),
00959 SLOT(slotSetAnnotationResult(KIO::Job *)));
00960 break;
00961 }
00962 }
00963
00964 case SYNC_STATE_SET_ACLS:
00965 mSyncState = SYNC_STATE_GET_ACLS;
00966
00967 if( !noContent() && mAccount->hasACLSupport() &&
00968 ( mUserRights <= 0 || ( mUserRights & ACLJobs::Administer ) ) ) {
00969 bool hasChangedACLs = false;
00970 ACLList::ConstIterator it = mACLList.begin();
00971 for ( ; it != mACLList.end() && !hasChangedACLs; ++it ) {
00972 hasChangedACLs = (*it).changed;
00973 }
00974 if ( hasChangedACLs ) {
00975 newState( mProgress, i18n("Setting permissions"));
00976 KURL url = mAccount->getUrl();
00977 url.setPath( imapPath() );
00978 KIO::Job* job = KMail::ACLJobs::multiSetACL( mAccount->slave(), url, mACLList );
00979 ImapAccountBase::jobData jd( url.url(), folder() );
00980 mAccount->insertJob(job, jd);
00981
00982 connect(job, SIGNAL(result(KIO::Job *)),
00983 SLOT(slotMultiSetACLResult(KIO::Job *)));
00984 connect(job, SIGNAL(aclChanged( const QString&, int )),
00985 SLOT(slotACLChanged( const QString&, int )) );
00986 break;
00987 }
00988 }
00989
00990 case SYNC_STATE_GET_ACLS:
00991
00992 mSyncState = SYNC_STATE_FIND_SUBFOLDERS;
00993
00994 if( !noContent() && mAccount->hasACLSupport() ) {
00995 newState( mProgress, i18n( "Retrieving permissions" ) );
00996 mAccount->getACL( folder(), mImapPath );
00997 connect( mAccount, SIGNAL(receivedACL( KMFolder*, KIO::Job*, const KMail::ACLList& )),
00998 this, SLOT(slotReceivedACL( KMFolder*, KIO::Job*, const KMail::ACLList& )) );
00999 break;
01000 }
01001
01002 case SYNC_STATE_FIND_SUBFOLDERS:
01003 {
01004 mProgress = 98;
01005 newState( mProgress, i18n("Updating cache file"));
01006
01007 mSyncState = SYNC_STATE_SYNC_SUBFOLDERS;
01008 mSubfoldersForSync.clear();
01009 mCurrentSubfolder = 0;
01010 if( folder() && folder()->child() ) {
01011 KMFolderNode *node = folder()->child()->first();
01012 while( node ) {
01013 if( !node->isDir() ) {
01014 KMFolderCachedImap* storage = static_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage());
01015
01016 if ( !storage->imapPath().isEmpty()
01017
01018 && !foldersForDeletionOnServer.contains( storage->imapPath() ) ) {
01019 mSubfoldersForSync << storage;
01020 } else {
01021 kdDebug(5006) << "Do not add " << storage->label()
01022 << " to synclist" << endl;
01023 }
01024 }
01025 node = folder()->child()->next();
01026 }
01027 }
01028
01029
01030 mProgress = 100;
01031 newState( mProgress, i18n("Synchronization done"));
01032 KURL url = mAccount->getUrl();
01033 url.setPath( imapPath() );
01034 kmkernel->iCalIface().folderSynced( folder(), url );
01035 }
01036
01037 if ( !mRecurse )
01038 mSubfoldersForSync.clear();
01039
01040
01041 case SYNC_STATE_SYNC_SUBFOLDERS:
01042 {
01043 if( mCurrentSubfolder ) {
01044 disconnect( mCurrentSubfolder, SIGNAL( folderComplete(KMFolderCachedImap*, bool) ),
01045 this, SLOT( slotSubFolderComplete(KMFolderCachedImap*, bool) ) );
01046 mCurrentSubfolder = 0;
01047 }
01048
01049 if( mSubfoldersForSync.isEmpty() ) {
01050 mSyncState = SYNC_STATE_INITIAL;
01051 mAccount->addUnreadMsgCount( this, countUnread() );
01052 close();
01053 emit folderComplete( this, true );
01054 } else {
01055 mCurrentSubfolder = mSubfoldersForSync.front();
01056 mSubfoldersForSync.pop_front();
01057 connect( mCurrentSubfolder, SIGNAL( folderComplete(KMFolderCachedImap*, bool) ),
01058 this, SLOT( slotSubFolderComplete(KMFolderCachedImap*, bool) ) );
01059
01060
01061 assert( !mCurrentSubfolder->imapPath().isEmpty() );
01062 mCurrentSubfolder->setAccount( account() );
01063 bool recurse = mCurrentSubfolder->noChildren() ? false : true;
01064 mCurrentSubfolder->serverSync( recurse );
01065 }
01066 }
01067 break;
01068
01069 default:
01070 kdDebug(5006) << "KMFolderCachedImap::serverSyncInternal() WARNING: no such state "
01071 << mSyncState << endl;
01072 }
01073 }
01074
01075
01076
01077
01078 void KMFolderCachedImap::slotConnectionResult( int errorCode, const QString& errorMsg )
01079 {
01080 disconnect( mAccount, SIGNAL( connectionResult(int, const QString&) ),
01081 this, SLOT( slotConnectionResult(int, const QString&) ) );
01082 if ( !errorCode ) {
01083
01084 mSyncState = SYNC_STATE_GET_USERRIGHTS;
01085 mProgress += 5;
01086 serverSyncInternal();
01087 } else {
01088
01089 newState( mProgress, KIO::buildErrorString( errorCode, errorMsg ));
01090 emit folderComplete(this, FALSE);
01091 }
01092 }
01093
01094
01095 QValueList<unsigned long> KMFolderCachedImap::findNewMessages()
01096 {
01097 QValueList<unsigned long> result;
01098 for( int i = 0; i < count(); ++i ) {
01099 KMMsgBase *msg = getMsgBase( i );
01100 if( !msg ) continue;
01101 if ( msg->UID() == 0 )
01102 result.append( msg->getMsgSerNum() );
01103 }
01104 return result;
01105 }
01106
01107
01108 void KMFolderCachedImap::uploadNewMessages()
01109 {
01110 QValueList<unsigned long> newMsgs = findNewMessages();
01111 if( !newMsgs.isEmpty() ) {
01112 if ( mUserRights <= 0 || ( mUserRights & ( KMail::ACLJobs::Insert ) ) ) {
01113 newState( mProgress, i18n("Uploading messages to server"));
01114 CachedImapJob *job = new CachedImapJob( newMsgs, CachedImapJob::tPutMessage, this );
01115 connect( job, SIGNAL( progress( unsigned long, unsigned long) ),
01116 this, SLOT( slotPutProgress(unsigned long, unsigned long) ) );
01117 connect( job, SIGNAL( finished() ), this, SLOT( serverSyncInternal() ) );
01118 job->start();
01119 return;
01120 } else {
01121 const QString msg ( i18n( "<p>There are new messages in this folder (%1), which "
01122 "have not been uploaded to the server yet, but you do not seem to "
01123 "have sufficient access rights on the folder now to upload them. "
01124 "Please contact your administrator to allow upload of new messages "
01125 "to you, or move them out of this folder.</p> "
01126 "<p>Do you want to move these messages to another folder now?</p>").arg( folder()->prettyURL() ) );
01127 if ( KMessageBox::warningYesNo( 0, msg, QString::null, i18n("Move"), i18n("Do Not Move") ) == KMessageBox::Yes ) {
01128 KMail::KMFolderSelDlg dlg( kmkernel->getKMMainWidget(),
01129 i18n("Move Messages to Folder"), true );
01130 if ( dlg.exec() ) {
01131 KMFolder* dest = dlg.folder();
01132 if ( dest ) {
01133 QPtrList<KMMsgBase> msgs;
01134 for( int i = 0; i < count(); ++i ) {
01135 KMMsgBase *msg = getMsgBase( i );
01136 if( !msg ) continue;
01137 if ( msg->UID() == 0 )
01138 msgs.append( msg );
01139 }
01140 KMCommand *command = new KMMoveCommand( dest, msgs );
01141 connect( command, SIGNAL( completed( KMCommand * ) ),
01142 this, SLOT( serverSyncInternal() ) );
01143 command->start();
01144 return;
01145 }
01146 }
01147 }
01148 }
01149 }
01150 newState( mProgress, i18n("No messages to upload to server"));
01151 serverSyncInternal();
01152 }
01153
01154
01155 void KMFolderCachedImap::slotPutProgress( unsigned long done, unsigned long total )
01156 {
01157
01158 int progressSpan = 10;
01159 newState( mProgress + (progressSpan * done) / total, QString::null );
01160 if ( done == total )
01161 mProgress += progressSpan;
01162 }
01163
01164
01165 void KMFolderCachedImap::uploadFlags()
01166 {
01167 if ( !uidMap.isEmpty() ) {
01168 mStatusFlagsJobs = 0;
01169 newState( mProgress, i18n("Uploading status of messages to server"));
01170
01171
01172 QMap< QString, QStringList > groups;
01173
01174 for( int i = 0; i < count(); ++i ) {
01175 KMMsgBase* msg = getMsgBase( i );
01176 if( !msg || msg->UID() == 0 )
01177
01178 continue;
01179
01180 QString flags = KMFolderImap::statusToFlags(msg->status());
01181
01182 QString uid;
01183 uid.setNum( msg->UID() );
01184 groups[flags].append(uid);
01185 }
01186 QMapIterator< QString, QStringList > dit;
01187 for( dit = groups.begin(); dit != groups.end(); ++dit ) {
01188 QCString flags = dit.key().latin1();
01189 QStringList sets = KMFolderImap::makeSets( (*dit), true );
01190 mStatusFlagsJobs += sets.count();
01191
01192 for( QStringList::Iterator slit = sets.begin(); slit != sets.end(); ++slit ) {
01193 QString imappath = imapPath() + ";UID=" + ( *slit );
01194 mAccount->setImapStatus(folder(), imappath, flags);
01195 }
01196 }
01197
01198
01199 if ( mStatusFlagsJobs ) {
01200 connect( mAccount, SIGNAL( imapStatusChanged(KMFolder*, const QString&, bool) ),
01201 this, SLOT( slotImapStatusChanged(KMFolder*, const QString&, bool) ) );
01202 return;
01203 }
01204 }
01205 newState( mProgress, i18n("No messages to upload to server"));
01206 serverSyncInternal();
01207 }
01208
01209 void KMFolderCachedImap::slotImapStatusChanged(KMFolder* folder, const QString&, bool cont)
01210 {
01211 if ( mSyncState == SYNC_STATE_INITIAL ){
01212 kdDebug(5006) << "IMAP status changed but reset " << endl;
01213 return;
01214 }
01215 if ( folder->storage() == this ) {
01216 --mStatusFlagsJobs;
01217 if ( mStatusFlagsJobs == 0 || !cont )
01218 disconnect( mAccount, SIGNAL( imapStatusChanged(KMFolder*, const QString&, bool) ),
01219 this, SLOT( slotImapStatusChanged(KMFolder*, const QString&, bool) ) );
01220 if ( mStatusFlagsJobs == 0 && cont ) {
01221 mProgress += 5;
01222 serverSyncInternal();
01223 }
01224 }
01225 }
01226
01227
01228 void KMFolderCachedImap::setStatus( int idx, KMMsgStatus status, bool toggle)
01229 {
01230 KMFolderMaildir::setStatus( idx, status, toggle );
01231 mStatusChangedLocally = true;
01232 }
01233
01234 void KMFolderCachedImap::setStatus(QValueList<int>& ids, KMMsgStatus status, bool toggle)
01235 {
01236 KMFolderMaildir::setStatus(ids, status, toggle);
01237 mStatusChangedLocally = true;
01238 }
01239
01240
01241 void KMFolderCachedImap::createNewFolders()
01242 {
01243 QValueList<KMFolderCachedImap*> newFolders = findNewFolders();
01244
01245 if( !newFolders.isEmpty() ) {
01246 newState( mProgress, i18n("Creating subfolders on server"));
01247 CachedImapJob *job = new CachedImapJob( newFolders, CachedImapJob::tAddSubfolders, this );
01248 connect( job, SIGNAL( result(KMail::FolderJob *) ), this, SLOT( slotIncreaseProgress() ) );
01249 connect( job, SIGNAL( finished() ), this, SLOT( serverSyncInternal() ) );
01250 job->start();
01251 } else {
01252 serverSyncInternal();
01253 }
01254 }
01255
01256 QValueList<KMFolderCachedImap*> KMFolderCachedImap::findNewFolders()
01257 {
01258 QValueList<KMFolderCachedImap*> newFolders;
01259 if( folder() && folder()->child() ) {
01260 KMFolderNode *node = folder()->child()->first();
01261 while( node ) {
01262 if( !node->isDir() ) {
01263 if( static_cast<KMFolder*>(node)->folderType() != KMFolderTypeCachedImap ) {
01264 kdError(5006) << "KMFolderCachedImap::findNewFolders(): ARGH!!! "
01265 << node->name() << " is not an IMAP folder\n";
01266 node = folder()->child()->next();
01267 assert(0);
01268 }
01269 KMFolderCachedImap* folder = static_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage());
01270 if( folder->imapPath().isEmpty() ) {
01271 newFolders << folder;
01272 }
01273 }
01274 node = folder()->child()->next();
01275 }
01276 }
01277 return newFolders;
01278 }
01279
01280 bool KMFolderCachedImap::deleteMessages()
01281 {
01282 if ( mUserRights > 0 && !( mUserRights & KMail::ACLJobs::Delete ) )
01283 return false;
01284
01285 QPtrList<KMMessage> msgsForDeletion;
01286
01287
01288
01289
01290
01291 QMap<ulong,int>::const_iterator it = uidMap.constBegin();
01292 for( ; it != uidMap.end(); it++ ) {
01293 ulong uid ( it.key() );
01294 if( uid!=0 && !uidsOnServer.find( uid ) )
01295 msgsForDeletion.append( getMsg( *it ) );
01296 }
01297
01298 if( !msgsForDeletion.isEmpty() ) {
01299 removeMsg( msgsForDeletion );
01300 }
01301
01302
01303 if( !uidsForDeletionOnServer.isEmpty() ) {
01304 newState( mProgress, i18n("Deleting removed messages from server"));
01305 QStringList sets = KMFolderImap::makeSets( uidsForDeletionOnServer, true );
01306 uidsForDeletionOnServer.clear();
01307 kdDebug(5006) << "Deleting " << sets.count() << " sets of messages from server folder " << imapPath() << endl;
01308 CachedImapJob *job = new CachedImapJob( sets, CachedImapJob::tDeleteMessage, this );
01309 connect( job, SIGNAL( result(KMail::FolderJob *) ),
01310 this, SLOT( slotDeleteMessagesResult(KMail::FolderJob *) ) );
01311 job->start();
01312 return true;
01313 } else {
01314 return false;
01315 }
01316 }
01317
01318 void KMFolderCachedImap::slotDeleteMessagesResult( KMail::FolderJob* job )
01319 {
01320 if ( job->error() ) {
01321
01322 mSyncState = SYNC_STATE_GET_MESSAGES;
01323 }
01324 mProgress += 10;
01325 serverSyncInternal();
01326 }
01327
01328 void KMFolderCachedImap::checkUidValidity() {
01329
01330
01331 if( imapPath().isEmpty() || imapPath() == "/" )
01332
01333 serverSyncInternal();
01334 else {
01335 newState( mProgress, i18n("Checking folder validity"));
01336 CachedImapJob *job = new CachedImapJob( FolderJob::tCheckUidValidity, this );
01337 connect( job, SIGNAL( result( KMail::FolderJob* ) ),
01338 this, SLOT( slotCheckUidValidityResult( KMail::FolderJob* ) ) );
01339 job->start();
01340 }
01341 }
01342
01343 void KMFolderCachedImap::slotCheckUidValidityResult( KMail::FolderJob* job )
01344 {
01345 if ( job->error() ) {
01346
01347
01348 mSyncState = SYNC_STATE_HANDLE_INBOX;
01349 }
01350 mProgress += 5;
01351 serverSyncInternal();
01352 }
01353
01354
01355
01356 void KMFolderCachedImap::listMessages() {
01357 if( imapPath() == "/" ) {
01358
01359 serverSyncInternal();
01360 return;
01361 }
01362
01363 if( !mAccount->slave() ) {
01364 resetSyncState();
01365 emit folderComplete( this, false );
01366 return;
01367 }
01368 uidsOnServer.clear();
01369 uidsOnServer.resize( count() * 2 );
01370 uidsForDeletionOnServer.clear();
01371 mMsgsForDownload.clear();
01372 mUidsForDownload.clear();
01373
01374 CachedImapJob* job = new CachedImapJob( FolderJob::tListMessages, this );
01375 connect( job, SIGNAL( result(KMail::FolderJob *) ),
01376 this, SLOT( slotGetLastMessagesResult(KMail::FolderJob *) ) );
01377 job->start();
01378 }
01379
01380 void KMFolderCachedImap::slotGetLastMessagesResult(KMail::FolderJob *job)
01381 {
01382 getMessagesResult(job, true);
01383 }
01384
01385
01386 void KMFolderCachedImap::slotGetMessagesData(KIO::Job * job, const QByteArray & data)
01387 {
01388 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
01389 if ( it == mAccount->jobsEnd() ) {
01390 kdDebug(5006) << "could not find job!?!?!" << endl;
01391
01392
01393
01394 mSyncState = SYNC_STATE_HANDLE_INBOX;
01395 serverSyncInternal();
01396 return;
01397 }
01398 (*it).cdata += QCString(data, data.size() + 1);
01399 int pos = (*it).cdata.find("\r\n--IMAPDIGEST");
01400 if (pos > 0) {
01401 int a = (*it).cdata.find("\r\nX-uidValidity:");
01402 if (a != -1) {
01403 int b = (*it).cdata.find("\r\n", a + 17);
01404 setUidValidity((*it).cdata.mid(a + 17, b - a - 17));
01405 }
01406 a = (*it).cdata.find("\r\nX-Access:");
01407
01408
01409
01410
01411
01412 if (a != -1 && mUserRights == -1 ) {
01413 int b = (*it).cdata.find("\r\n", a + 12);
01414 const QString access = (*it).cdata.mid(a + 12, b - a - 12);
01415 setReadOnly( access == "Read only" );
01416 }
01417 (*it).cdata.remove(0, pos);
01418 }
01419 pos = (*it).cdata.find("\r\n--IMAPDIGEST", 1);
01420
01421 if ( uidsOnServer.size() == 0 )
01422 uidsOnServer.resize( KMail::nextPrime( 2000 ) );
01423 int flags;
01424 const int v = 42;
01425 while (pos >= 0) {
01426 KMMessage msg;
01427 msg.fromString((*it).cdata.mid(16, pos - 16));
01428 flags = msg.headerField("X-Flags").toInt();
01429 bool deleted = ( flags & 8 );
01430 ulong uid = msg.UID();
01431 if ( !deleted ) {
01432 if( uid != 0 ) {
01433 if ( uidsOnServer.count() == uidsOnServer.size() ) {
01434 uidsOnServer.resize( KMail::nextPrime( uidsOnServer.size() * 2 ) );
01435 kdDebug( 5006 ) << "Resizing to: " << uidsOnServer.size() << endl;
01436 }
01437 uidsOnServer.insert( uid, &v );
01438 }
01439 bool redownload = false;
01440 if ( uid <= lastUid() ) {
01441
01442
01443
01444
01445
01446
01447
01448
01449
01450
01451 KMMsgBase *existingMessage = findByUID(uid);
01452 if( !existingMessage ) {
01453 if ( mUserRights <= 0 || ( mUserRights & KMail::ACLJobs::Delete ) ) {
01454
01455 uidsForDeletionOnServer << uid;
01456 } else {
01457 redownload = true;
01458 }
01459 } else {
01460
01461
01462
01463 if (!mReadOnly) {
01464
01465 KMFolderImap::flagsToStatus( existingMessage, flags );
01466 }
01467 }
01468
01469 }
01470 if ( uid > lastUid() || redownload ) {
01471
01472
01473 if ( !uidMap.contains( uid ) ) {
01474 ulong size = msg.headerField("X-Length").toULong();
01475 mMsgsForDownload << KMail::CachedImapJob::MsgForDownload(uid, flags, size);
01476 if( imapPath() == "/INBOX/" )
01477 mUidsForDownload << uid;
01478 }
01479
01480 if ( uid > mTentativeHighestUid )
01481 mTentativeHighestUid = uid;
01482 }
01483 }
01484 (*it).cdata.remove(0, pos);
01485 (*it).done++;
01486 pos = (*it).cdata.find("\r\n--IMAPDIGEST", 1);
01487 }
01488 }
01489
01490 void KMFolderCachedImap::getMessagesResult( KMail::FolderJob *job, bool lastSet )
01491 {
01492 mProgress += 10;
01493 if( job->error() ) {
01494 mContentState = imapNoInformation;
01495 mSyncState = SYNC_STATE_HANDLE_INBOX;
01496 } else {
01497 if( lastSet ) {
01498 mContentState = imapFinished;
01499 mStatusChangedLocally = false;
01500 }
01501 }
01502 serverSyncInternal();
01503 }
01504
01505 void KMFolderCachedImap::slotProgress(unsigned long done, unsigned long total)
01506 {
01507 int progressSpan = 100 - 5 - mProgress;
01508
01509
01510
01511 newState( mProgress + (progressSpan * done) / total, QString::null );
01512 }
01513
01514
01515 void KMFolderCachedImap::setAccount(KMAcctCachedImap *aAccount)
01516 {
01517 assert( aAccount->isA("KMAcctCachedImap") );
01518 mAccount = aAccount;
01519 if( imapPath()=="/" ) aAccount->setFolder( folder() );
01520
01521
01522 QString newName = mAccount->renamedFolder( imapPath() );
01523 if ( !newName.isEmpty() )
01524 folder()->setLabel( newName );
01525
01526 if( !folder() || !folder()->child() || !folder()->child()->count() ) return;
01527 for( KMFolderNode* node = folder()->child()->first(); node;
01528 node = folder()->child()->next() )
01529 if (!node->isDir())
01530 static_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage())->setAccount(aAccount);
01531 }
01532
01533 void KMFolderCachedImap::listNamespaces()
01534 {
01535 ImapAccountBase::ListType type = ImapAccountBase::List;
01536 if ( mAccount->onlySubscribedFolders() )
01537 type = ImapAccountBase::ListSubscribed;
01538
01539 kdDebug(5006) << "listNamespaces " << mNamespacesToList << endl;
01540 if ( mNamespacesToList.isEmpty() ) {
01541 mSyncState = SYNC_STATE_DELETE_SUBFOLDERS;
01542 mPersonalNamespacesCheckDone = true;
01543
01544 QStringList ns = mAccount->namespaces()[ImapAccountBase::OtherUsersNS];
01545 ns += mAccount->namespaces()[ImapAccountBase::SharedNS];
01546 mNamespacesToCheck = ns.count();
01547 for ( QStringList::Iterator it = ns.begin(); it != ns.end(); ++it )
01548 {
01549 if ( (*it).isEmpty() ) {
01550
01551 --mNamespacesToCheck;
01552 continue;
01553 }
01554 KMail::ListJob* job = new KMail::ListJob( mAccount, type, this, mAccount->addPathToNamespace( *it ) );
01555 connect( job, SIGNAL(receivedFolders(const QStringList&, const QStringList&,
01556 const QStringList&, const QStringList&, const ImapAccountBase::jobData&)),
01557 this, SLOT(slotCheckNamespace(const QStringList&, const QStringList&,
01558 const QStringList&, const QStringList&, const ImapAccountBase::jobData&)));
01559 job->start();
01560 }
01561 if ( mNamespacesToCheck == 0 ) {
01562 serverSyncInternal();
01563 }
01564 return;
01565 }
01566 mPersonalNamespacesCheckDone = false;
01567
01568 QString ns = mNamespacesToList.front();
01569 mNamespacesToList.pop_front();
01570
01571 mSyncState = SYNC_STATE_LIST_SUBFOLDERS2;
01572 newState( mProgress, i18n("Retrieving folders for namespace %1").arg(ns));
01573 KMail::ListJob* job = new KMail::ListJob( mAccount, type, this,
01574 mAccount->addPathToNamespace( ns ) );
01575 job->setNamespace( ns );
01576 connect( job, SIGNAL(receivedFolders(const QStringList&, const QStringList&,
01577 const QStringList&, const QStringList&, const ImapAccountBase::jobData&)),
01578 this, SLOT(slotListResult(const QStringList&, const QStringList&,
01579 const QStringList&, const QStringList&, const ImapAccountBase::jobData&)));
01580 job->start();
01581 }
01582
01583 void KMFolderCachedImap::slotCheckNamespace( const QStringList& subfolderNames,
01584 const QStringList& subfolderPaths,
01585 const QStringList& subfolderMimeTypes,
01586 const QStringList& subfolderAttributes,
01587 const ImapAccountBase::jobData& jobData )
01588 {
01589 Q_UNUSED( subfolderPaths );
01590 Q_UNUSED( subfolderMimeTypes );
01591 Q_UNUSED( subfolderAttributes );
01592 --mNamespacesToCheck;
01593 kdDebug(5006) << "slotCheckNamespace " << subfolderNames << ",remain=" <<
01594 mNamespacesToCheck << endl;
01595
01596
01597
01598 QString name = jobData.path.mid( 1, jobData.path.length()-2 );
01599 name.remove( mAccount->delimiterForNamespace( name ) );
01600 if ( name.isEmpty() ) {
01601
01602 kdWarning(5006) << "slotCheckNamespace: ignoring empty folder!" << endl;
01603 return;
01604 }
01605
01606 folder()->createChildFolder();
01607 KMFolderNode *node = 0;
01608 for ( node = folder()->child()->first(); node;
01609 node = folder()->child()->next())
01610 {
01611 if ( !node->isDir() && node->name() == name )
01612 break;
01613 }
01614 if ( !subfolderNames.isEmpty() ) {
01615 if ( node ) {
01616
01617 kdDebug(5006) << "found namespace folder " << name << endl;
01618 } else
01619 {
01620
01621 kdDebug(5006) << "create namespace folder " << name << endl;
01622 KMFolder* newFolder = folder()->child()->createFolder( name, false,
01623 KMFolderTypeCachedImap );
01624 if ( newFolder ) {
01625 KMFolderCachedImap *f = static_cast<KMFolderCachedImap*>( newFolder->storage() );
01626 f->setImapPath( mAccount->addPathToNamespace( name ) );
01627 f->setNoContent( true );
01628 f->setAccount( mAccount );
01629 f->close();
01630 kmkernel->dimapFolderMgr()->contentsChanged();
01631 }
01632 }
01633 } else {
01634 if ( node ) {
01635 kdDebug(5006) << "delete namespace folder " << name << endl;
01636 KMFolder* fld = static_cast<KMFolder*>(node);
01637 kmkernel->dimapFolderMgr()->remove( fld );
01638 }
01639 }
01640
01641 if ( mNamespacesToCheck == 0 ) {
01642
01643 serverSyncInternal();
01644 }
01645 }
01646
01647
01648
01649 bool KMFolderCachedImap::listDirectory()
01650 {
01651 if( !mAccount->slave() ) {
01652 resetSyncState();
01653 emit folderComplete( this, false );
01654 return false;
01655 }
01656 mSubfolderState = imapInProgress;
01657
01658
01659 ImapAccountBase::ListType type = ImapAccountBase::List;
01660 if ( mAccount->onlySubscribedFolders() )
01661 type = ImapAccountBase::ListSubscribed;
01662 KMail::ListJob* job = new KMail::ListJob( mAccount, type, this );
01663 connect( job, SIGNAL(receivedFolders(const QStringList&, const QStringList&,
01664 const QStringList&, const QStringList&, const ImapAccountBase::jobData&)),
01665 this, SLOT(slotListResult(const QStringList&, const QStringList&,
01666 const QStringList&, const QStringList&, const ImapAccountBase::jobData&)));
01667 job->start();
01668
01669 return true;
01670 }
01671
01672 void KMFolderCachedImap::slotListResult( const QStringList& folderNames,
01673 const QStringList& folderPaths,
01674 const QStringList& folderMimeTypes,
01675 const QStringList& folderAttributes,
01676 const ImapAccountBase::jobData& jobData )
01677 {
01678 Q_UNUSED( jobData );
01679
01680
01681 mSubfolderNames = folderNames;
01682 mSubfolderPaths = folderPaths;
01683 mSubfolderMimeTypes = folderMimeTypes;
01684 mSubfolderAttributes = folderAttributes;
01685
01686 mSubfolderState = imapFinished;
01687
01688 folder()->createChildFolder();
01689 KMFolderNode *node = folder()->child()->first();
01690 bool root = ( this == mAccount->rootFolder() );
01691
01692 QPtrList<KMFolder> toRemove;
01693 bool emptyList = ( root && mSubfolderNames.empty() );
01694 if ( !emptyList ) {
01695 while (node) {
01696 if (!node->isDir() ) {
01697 KMFolderCachedImap *f = static_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage());
01698
01699 if ( mSubfolderNames.findIndex(node->name()) == -1 ) {
01700 QString name = node->name();
01701
01702
01703 bool isInNamespace = ( jobData.curNamespace.isEmpty() ||
01704 jobData.curNamespace == mAccount->namespaceForFolder( f ) );
01705
01706 bool ignore = root && ( f->imapPath() == "/INBOX/" ||
01707 mAccount->isNamespaceFolder( name ) || !isInNamespace );
01708
01709
01710 if( !f->imapPath().isEmpty() && !ignore ) {
01711
01712
01713 toRemove.append( f->folder() );
01714 kdDebug(5006) << node->name() << " isn't on the server. It has an imapPath -> delete it locally" << endl;
01715 }
01716 } else {
01717
01718 }
01719 } else {
01720
01721 }
01722 node = folder()->child()->next();
01723 }
01724 }
01725
01726 for ( KMFolder* doomed=toRemove.first(); doomed; doomed = toRemove.next() ) {
01727 kmkernel->dimapFolderMgr()->remove( doomed );
01728 }
01729
01730 mProgress += 5;
01731 serverSyncInternal();
01732 }
01733
01734
01735 void KMFolderCachedImap::listDirectory2()
01736 {
01737 QString path = folder()->path();
01738 KMFolderCachedImap *f = 0;
01739 kmkernel->dimapFolderMgr()->quiet(true);
01740
01741 KMFolderNode *node;
01742 bool root = ( this == mAccount->rootFolder() );
01743 if ( root && !mAccount->hasInbox() ) {
01744 kdDebug(5006) << "check INBOX" << endl;
01745
01746 for (node = folder()->child()->first(); node; node = folder()->child()->next())
01747 if (!node->isDir() && node->name() == "INBOX") break;
01748 if (node) {
01749 f = static_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage());
01750 } else {
01751 KMFolder* newFolder = folder()->child()->createFolder("INBOX", true, KMFolderTypeCachedImap);
01752 if ( newFolder ) {
01753 f = static_cast<KMFolderCachedImap*>(newFolder->storage());
01754 }
01755 }
01756 if ( f ) {
01757 f->setAccount( mAccount );
01758 f->setImapPath( "/INBOX/" );
01759 f->folder()->setLabel( i18n("inbox") );
01760 }
01761 if (!node) {
01762 if ( f )
01763 f->close();
01764 kmkernel->dimapFolderMgr()->contentsChanged();
01765 }
01766
01767 mAccount->setHasInbox( true );
01768 }
01769
01770 if ( root && !mSubfolderNames.isEmpty() ) {
01771 KMFolderCachedImap* parent =
01772 findParent( mSubfolderPaths.first(), mSubfolderNames.first() );
01773 if ( parent ) {
01774 kdDebug(5006) << "KMFolderCachedImap::listDirectory2 - pass listing to "
01775 << parent->label() << endl;
01776 mSubfolderNames.clear();
01777 }
01778 }
01779
01780
01781 for (uint i = 0; i < mSubfolderNames.count(); i++) {
01782
01783
01784 for (node = folder()->child()->first(); node;
01785 node = folder()->child()->next())
01786 if (!node->isDir() && node->name() == mSubfolderNames[i]) break;
01787
01788 if (!node) {
01789
01790
01791 QString subfolderPath = mSubfolderPaths[i];
01792
01793
01794
01795 bool locallyDeleted = mAccount->isDeletedFolder( subfolderPath );
01796
01797
01798
01799 if ( !locallyDeleted && mAccount->isPreviouslyDeletedFolder( subfolderPath ) ) {
01800 locallyDeleted = KMessageBox::warningYesNo(
01801 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;
01802 }
01803
01804 if ( locallyDeleted ) {
01805 kdDebug(5006) << subfolderPath << " was deleted locally => delete on server." << endl;
01806 foldersForDeletionOnServer += mAccount->deletedFolderPaths( subfolderPath );
01807 } else {
01808 kdDebug(5006) << subfolderPath << " is a new folder on the server => create local cache" << endl;
01809 KMFolder* newFolder = folder()->child()->createFolder(mSubfolderNames[i], false, KMFolderTypeCachedImap);
01810 if ( newFolder ) {
01811 f = static_cast<KMFolderCachedImap*>(newFolder->storage());
01812 }
01813 if (f) {
01814 f->close();
01815 f->setAccount(mAccount);
01816 kmkernel->dimapFolderMgr()->contentsChanged();
01817 f->mAnnotationFolderType = "FROMSERVER";
01818
01819 } else {
01820 kdDebug(5006) << "can't create folder " << mSubfolderNames[i] <<endl;
01821 }
01822 }
01823 } else {
01824 if( static_cast<KMFolder*>(node)->folderType() == KMFolderTypeCachedImap )
01825 f = static_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage());
01826 }
01827
01828 if( f ) {
01829
01830
01831
01832 f->setAccount(mAccount);
01833 f->setNoContent(mSubfolderMimeTypes[i] == "inode/directory");
01834 f->setNoChildren(mSubfolderMimeTypes[i] == "message/digest");
01835 f->setImapPath(mSubfolderPaths[i]);
01836 }
01837 }
01838 kmkernel->dimapFolderMgr()->quiet(false);
01839 emit listComplete(this);
01840 if ( !mPersonalNamespacesCheckDone ) {
01841
01842 mSyncState = SYNC_STATE_LIST_NAMESPACES;
01843 }
01844 serverSyncInternal();
01845 }
01846
01847
01848 KMFolderCachedImap* KMFolderCachedImap::findParent( const QString& path,
01849 const QString& name )
01850 {
01851 QString parent = path.left( path.length() - name.length() - 2 );
01852 if ( parent.length() > 1 )
01853 {
01854
01855 parent = parent.right( parent.length() - 1 );
01856 if ( parent != label() )
01857 {
01858 KMFolderNode *node = folder()->child()->first();
01859
01860 while ( node )
01861 {
01862 if ( node->name() == parent )
01863 {
01864 KMFolder* fld = static_cast<KMFolder*>(node);
01865 KMFolderCachedImap* imapFld =
01866 static_cast<KMFolderCachedImap*>( fld->storage() );
01867 return imapFld;
01868 }
01869 node = folder()->child()->next();
01870 }
01871 }
01872 }
01873 return 0;
01874 }
01875
01876 void KMFolderCachedImap::slotSubFolderComplete(KMFolderCachedImap* sub, bool success)
01877 {
01878 Q_UNUSED(sub);
01879
01880 if ( success ) {
01881 serverSyncInternal();
01882 }
01883 else
01884 {
01885
01886 if ( mCurrentSubfolder ) {
01887 Q_ASSERT( sub == mCurrentSubfolder );
01888 disconnect( mCurrentSubfolder, SIGNAL( folderComplete(KMFolderCachedImap*, bool) ),
01889 this, SLOT( slotSubFolderComplete(KMFolderCachedImap*, bool) ) );
01890 mCurrentSubfolder = 0;
01891 }
01892
01893 mSubfoldersForSync.clear();
01894 mSyncState = SYNC_STATE_INITIAL;
01895 close();
01896 emit folderComplete( this, false );
01897 }
01898 }
01899
01900 void KMFolderCachedImap::slotSimpleData(KIO::Job * job, const QByteArray & data)
01901 {
01902 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
01903 if (it == mAccount->jobsEnd()) return;
01904 QBuffer buff((*it).data);
01905 buff.open(IO_WriteOnly | IO_Append);
01906 buff.writeBlock(data.data(), data.size());
01907 buff.close();
01908 }
01909
01910
01911 FolderJob*
01912 KMFolderCachedImap::doCreateJob( KMMessage *msg, FolderJob::JobType jt, KMFolder *folder,
01913 QString, const AttachmentStrategy* ) const
01914 {
01915 QPtrList<KMMessage> msgList;
01916 msgList.append( msg );
01917 CachedImapJob *job = new CachedImapJob( msgList, jt, folder? static_cast<KMFolderCachedImap*>( folder->storage() ):0 );
01918 job->setParentFolder( this );
01919 return job;
01920 }
01921
01922 FolderJob*
01923 KMFolderCachedImap::doCreateJob( QPtrList<KMMessage>& msgList, const QString& sets,
01924 FolderJob::JobType jt, KMFolder *folder ) const
01925 {
01926
01927 Q_UNUSED( sets );
01928 CachedImapJob *job = new CachedImapJob( msgList, jt, folder? static_cast<KMFolderCachedImap*>( folder->storage() ):0 );
01929 job->setParentFolder( this );
01930 return job;
01931 }
01932
01933 void
01934 KMFolderCachedImap::setUserRights( unsigned int userRights )
01935 {
01936 mUserRights = userRights;
01937 }
01938
01939 void
01940 KMFolderCachedImap::slotReceivedUserRights( KMFolder* folder )
01941 {
01942 if ( folder->storage() == this ) {
01943 disconnect( mAccount, SIGNAL( receivedUserRights( KMFolder* ) ),
01944 this, SLOT( slotReceivedUserRights( KMFolder* ) ) );
01945 if ( mUserRights == 0 )
01946 mUserRights = -1;
01947 else
01948 setReadOnly( ( mUserRights & KMail::ACLJobs::Insert ) == 0 );
01949 mProgress += 5;
01950 serverSyncInternal();
01951 }
01952 }
01953
01954 void
01955 KMFolderCachedImap::setReadOnly( bool readOnly )
01956 {
01957 if ( readOnly != mReadOnly ) {
01958 mReadOnly = readOnly;
01959 emit readOnlyChanged( folder() );
01960 }
01961 }
01962
01963 void
01964 KMFolderCachedImap::slotReceivedACL( KMFolder* folder, KIO::Job*, const KMail::ACLList& aclList )
01965 {
01966 if ( folder->storage() == this ) {
01967 disconnect( mAccount, SIGNAL(receivedACL( KMFolder*, KIO::Job*, const KMail::ACLList& )),
01968 this, SLOT(slotReceivedACL( KMFolder*, KIO::Job*, const KMail::ACLList& )) );
01969 mACLList = aclList;
01970 serverSyncInternal();
01971 }
01972 }
01973
01974 void
01975 KMFolderCachedImap::setACLList( const ACLList& arr )
01976 {
01977 mACLList = arr;
01978 }
01979
01980 void
01981 KMFolderCachedImap::slotMultiSetACLResult(KIO::Job *job)
01982 {
01983 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
01984 if ( it == mAccount->jobsEnd() ) return;
01985 if ( (*it).parent != folder() ) return;
01986
01987 if ( job->error() )
01988
01989
01990 job->showErrorDialog();
01991 else
01992 kmkernel->iCalIface().addFolderChange( folder(), KMailICalIfaceImpl::ACL );
01993
01994 if (mAccount->slave()) mAccount->removeJob(job);
01995 serverSyncInternal();
01996 }
01997
01998 void
01999 KMFolderCachedImap::slotACLChanged( const QString& userId, int permissions )
02000 {
02001
02002
02003 for( ACLList::Iterator it = mACLList.begin(); it != mACLList.end(); ++it ) {
02004 if ( (*it).userId == userId && (*it).permissions == permissions ) {
02005 if ( permissions == -1 )
02006 mACLList.erase( it );
02007 else
02008 (*it).changed = false;
02009 return;
02010 }
02011 }
02012 }
02013
02014
02015 void KMFolderCachedImap::resetSyncState()
02016 {
02017 if ( mSyncState == SYNC_STATE_INITIAL ) return;
02018 mSubfoldersForSync.clear();
02019 mSyncState = SYNC_STATE_INITIAL;
02020 close();
02021
02022 KPIM::ProgressItem *progressItem = mAccount->mailCheckProgressItem();
02023 QString str = i18n("Aborted");
02024 if (progressItem)
02025 progressItem->setStatus( str );
02026 emit statusMsg( str );
02027 }
02028
02029 void KMFolderCachedImap::slotIncreaseProgress()
02030 {
02031 mProgress += 5;
02032 }
02033
02034 void KMFolderCachedImap::newState( int progress, const QString& syncStatus )
02035 {
02036
02037 KPIM::ProgressItem *progressItem = mAccount->mailCheckProgressItem();
02038 if( progressItem )
02039 progressItem->setCompletedItems( progress );
02040 if ( !syncStatus.isEmpty() ) {
02041 QString str;
02042
02043 if ( mAccount->imapFolder() == this )
02044 str = syncStatus;
02045 else
02046 str = QString( "%1: %2" ).arg( label() ).arg( syncStatus );
02047 if( progressItem )
02048 progressItem->setStatus( str );
02049 emit statusMsg( str );
02050 }
02051 if( progressItem )
02052 progressItem->updateProgress();
02053 }
02054
02055 void KMFolderCachedImap::setSubfolderState( imapState state )
02056 {
02057 mSubfolderState = state;
02058 if ( state == imapNoInformation && folder()->child() )
02059 {
02060
02061 KMFolderNode* node;
02062 QPtrListIterator<KMFolderNode> it( *folder()->child() );
02063 for ( ; (node = it.current()); )
02064 {
02065 ++it;
02066 if (node->isDir()) continue;
02067 KMFolder *folder = static_cast<KMFolder*>(node);
02068 static_cast<KMFolderCachedImap*>(folder->storage())->setSubfolderState( state );
02069 }
02070 }
02071 }
02072
02073 void KMFolderCachedImap::setImapPath(const QString &path)
02074 {
02075 mImapPath = path;
02076 }
02077
02078
02079
02080
02081
02082
02083 void KMFolderCachedImap::updateAnnotationFolderType()
02084 {
02085 QString oldType = mAnnotationFolderType;
02086 QString oldSubType;
02087 int dot = oldType.find( '.' );
02088 if ( dot != -1 ) {
02089 oldType.truncate( dot );
02090 oldSubType = mAnnotationFolderType.mid( dot + 1 );
02091 }
02092
02093 QString newType, newSubType;
02094
02095 if ( kmkernel->iCalIface().storageFormat( folder() ) == KMailICalIfaceImpl::StorageXML ) {
02096 newType = KMailICalIfaceImpl::annotationForContentsType( mContentsType );
02097 if ( kmkernel->iCalIface().isStandardResourceFolder( folder() ) )
02098 newSubType = "default";
02099 else
02100 newSubType = oldSubType;
02101 }
02102
02103
02104 if ( newType != oldType || newSubType != oldSubType ) {
02105 mAnnotationFolderType = newType + ( newSubType.isEmpty() ? QString::null : "."+newSubType );
02106 mAnnotationFolderTypeChanged = true;
02107 kdDebug(5006) << mImapPath << ": updateAnnotationFolderType: '" << mAnnotationFolderType << "', was (" << oldType << " " << oldSubType << ") => mAnnotationFolderTypeChanged set to TRUE" << endl;
02108 }
02109
02110 writeAnnotationConfig();
02111 }
02112
02113 void KMFolderCachedImap::setIncidencesFor( IncidencesFor incfor )
02114 {
02115 if ( mIncidencesFor != incfor ) {
02116 mIncidencesFor = incfor;
02117 mIncidencesForChanged = true;
02118 }
02119 }
02120
02121 void KMFolderCachedImap::slotAnnotationResult(const QString& entry, const QString& value, bool found)
02122 {
02123 if ( entry == KOLAB_FOLDERTYPE ) {
02124
02125
02126
02127
02128
02129 if ( found ) {
02130 QString type = value;
02131 QString subtype;
02132 int dot = value.find( '.' );
02133 if ( dot != -1 ) {
02134 type.truncate( dot );
02135 subtype = value.mid( dot + 1 );
02136 }
02137 bool foundKnownType = false;
02138 for ( uint i = 0 ; i <= ContentsTypeLast; ++i ) {
02139 FolderContentsType contentsType = static_cast<KMail::FolderContentsType>( i );
02140 if ( type == KMailICalIfaceImpl::annotationForContentsType( contentsType ) ) {
02141
02142
02143 if ( contentsType != ContentsTypeMail )
02144 kmkernel->iCalIface().setStorageFormat( folder(), KMailICalIfaceImpl::StorageXML );
02145 mAnnotationFolderType = value;
02146 if ( folder()->parent()->owner()->idString() != GlobalSettings::self()->theIMAPResourceFolderParent()
02147 && GlobalSettings::self()->theIMAPResourceEnabled()
02148 && subtype == "default" ) {
02149
02150
02151 mAnnotationFolderType = type;
02152 kdDebug(5006) << mImapPath << ": slotGetAnnotationResult: parent folder is " << folder()->parent()->owner()->idString() << " => truncating annotation to " << value << endl;
02153 }
02154 setContentsType( contentsType );
02155 mAnnotationFolderTypeChanged = false;
02156 foundKnownType = true;
02157
02158
02159
02160
02161
02162 if ( contentsType != ContentsTypeMail )
02163 markUnreadAsRead();
02164
02165
02166 writeAnnotationConfig();
02167 break;
02168 }
02169 }
02170 if ( !foundKnownType && !mReadOnly ) {
02171
02172
02173 mAnnotationFolderTypeChanged = true;
02174 }
02175
02176 }
02177 else if ( !mReadOnly ) {
02178
02179
02180 mAnnotationFolderTypeChanged = true;
02181 }
02182 } else if ( entry == KOLAB_INCIDENCESFOR ) {
02183 if ( found ) {
02184 mIncidencesFor = incidencesForFromString( value );
02185 Q_ASSERT( mIncidencesForChanged == false );
02186 }
02187 }
02188 }
02189
02190 void KMFolderCachedImap::slotGetAnnotationResult( KIO::Job* job )
02191 {
02192 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
02193 Q_ASSERT( it != mAccount->jobsEnd() );
02194 if ( it == mAccount->jobsEnd() ) return;
02195 Q_ASSERT( (*it).parent == folder() );
02196 if ( (*it).parent != folder() ) return;
02197
02198 AnnotationJobs::GetAnnotationJob* annjob = static_cast<AnnotationJobs::GetAnnotationJob *>( job );
02199 if ( annjob->error() ) {
02200 if ( job->error() == KIO::ERR_UNSUPPORTED_ACTION ) {
02201
02202 if ( GlobalSettings::self()->theIMAPResourceStorageFormat() == GlobalSettings::EnumTheIMAPResourceStorageFormat::XML
02203 && (uint)GlobalSettings::self()->theIMAPResourceAccount() == mAccount->id() )
02204 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() ) );
02205 mAccount->setHasNoAnnotationSupport();
02206 }
02207 else
02208 kdWarning(5006) << "slotGetAnnotationResult: " << job->errorString() << endl;
02209 }
02210
02211 if (mAccount->slave()) mAccount->removeJob(job);
02212 mProgress += 2;
02213 serverSyncInternal();
02214 }
02215
02216 void
02217 KMFolderCachedImap::slotAnnotationChanged( const QString& entry, const QString& attribute, const QString& value )
02218 {
02219 kdDebug(5006) << k_funcinfo << entry << " " << attribute << " " << value << endl;
02220 if ( entry == KOLAB_FOLDERTYPE )
02221 mAnnotationFolderTypeChanged = false;
02222 else if ( entry == KOLAB_INCIDENCESFOR ) {
02223 mIncidencesForChanged = false;
02224
02225
02226 kmkernel->iCalIface().addFolderChange( folder(), KMailICalIfaceImpl::ACL );
02227 }
02228 }
02229
02230 void KMFolderCachedImap::slotTestAnnotationResult(KIO::Job *job)
02231 {
02232 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
02233 Q_ASSERT( it != mAccount->jobsEnd() );
02234 if ( it == mAccount->jobsEnd() ) return;
02235 Q_ASSERT( (*it).parent == folder() );
02236 if ( (*it).parent != folder() ) return;
02237
02238 mAccount->setAnnotationCheckPassed( true );
02239 if ( job->error() ) {
02240 kdDebug(5006) << "Test Annotation was not passed, disabling annotation support" << endl;
02241 mAccount->setHasNoAnnotationSupport( );
02242 } else {
02243 kdDebug(5006) << "Test Annotation was passed OK" << endl;
02244 }
02245 if (mAccount->slave()) mAccount->removeJob(job);
02246 serverSyncInternal();
02247 }
02248
02249 void
02250 KMFolderCachedImap::slotSetAnnotationResult(KIO::Job *job)
02251 {
02252 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
02253 if ( it == mAccount->jobsEnd() ) return;
02254 if ( (*it).parent != folder() ) return;
02255
02256 bool cont = true;
02257 if ( job->error() ) {
02258
02259 if ( job->error() == KIO::ERR_UNSUPPORTED_ACTION && contentsType() == ContentsTypeMail )
02260 if (mAccount->slave()) mAccount->removeJob(job);
02261 else
02262 cont = mAccount->handleJobError( job, i18n( "Error while setting annotation: " ) + '\n' );
02263 } else {
02264 if (mAccount->slave()) mAccount->removeJob(job);
02265 }
02266 if ( cont )
02267 serverSyncInternal();
02268 }
02269
02270 void KMFolderCachedImap::slotUpdateLastUid()
02271 {
02272 if( mTentativeHighestUid != 0 )
02273 setLastUid( mTentativeHighestUid );
02274 mTentativeHighestUid = 0;
02275 }
02276
02277 bool KMFolderCachedImap::isMoveable() const
02278 {
02279 return ( hasChildren() == HasNoChildren &&
02280 !folder()->isSystemFolder() ) ? true : false;
02281 }
02282
02283 void KMFolderCachedImap::slotFolderDeletionOnServerFinished()
02284 {
02285 for ( QStringList::const_iterator it = foldersForDeletionOnServer.constBegin();
02286 it != foldersForDeletionOnServer.constEnd(); ++it ) {
02287 KURL url( mAccount->getUrl() );
02288 url.setPath( *it );
02289 kmkernel->iCalIface().folderDeletedOnServer( url );
02290 }
02291 serverSyncInternal();
02292 }
02293
02294 #include "kmfoldercachedimap.moc"