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