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