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