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