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