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