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