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