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() << " Going to locally delete " << msgsForDeletion.count()
01713 << " messages, with the uids " << uids.join( "," ) << endl;
01714 }
01715 if ( !GlobalSettings::self()->mailLossDebug() || KMessageBox::warningYesNo(
01716 0, i18n( "<qt><p>Mails on the server in folder <b>%1</b> were deleted. "
01717 "Do you want to delete them locally?<br>UIDs: %2</p></qt>" )
01718 .arg( folder()->prettyURL() ).arg( uids.join(",") ) ) == KMessageBox::Yes )
01719 removeMsg( msgsForDeletion );
01720 }
01721
01722 if ( mUserRightsState == KMail::ACLJobs::Ok && !( mUserRights & KMail::ACLJobs::Delete ) )
01723 return false;
01724
01725
01726 if( !uidsForDeletionOnServer.isEmpty() ) {
01727 newState( mProgress, i18n("Deleting removed messages from server"));
01728 QStringList sets = KMFolderImap::makeSets( uidsForDeletionOnServer, true );
01729 uidsForDeletionOnServer.clear();
01730 kdDebug(5006) << "Deleting " << sets.count() << " sets of messages from server folder " << imapPath() << endl;
01731 CachedImapJob *job = new CachedImapJob( sets, CachedImapJob::tDeleteMessage, this );
01732 connect( job, SIGNAL( result(KMail::FolderJob *) ),
01733 this, SLOT( slotDeleteMessagesResult(KMail::FolderJob *) ) );
01734 job->start();
01735 return true;
01736 } else {
01737
01738
01739
01740
01741 mDeletedUIDsSinceLastSync.clear();
01742 return false;
01743 }
01744 }
01745
01746 void KMFolderCachedImap::slotDeleteMessagesResult( KMail::FolderJob* job )
01747 {
01748 if ( job->error() ) {
01749
01750 mSyncState = SYNC_STATE_GET_MESSAGES;
01751 } else {
01752
01753 mDeletedUIDsSinceLastSync.clear();
01754 }
01755 mProgress += 10;
01756 serverSyncInternal();
01757 }
01758
01759 void KMFolderCachedImap::checkUidValidity() {
01760
01761
01762 if( imapPath().isEmpty() || imapPath() == "/" )
01763
01764 serverSyncInternal();
01765 else {
01766 newState( mProgress, i18n("Checking folder validity"));
01767 CachedImapJob *job = new CachedImapJob( FolderJob::tCheckUidValidity, this );
01768 connect( job, SIGNAL(permanentFlags(int)), SLOT(slotPermanentFlags(int)) );
01769 connect( job, SIGNAL( result( KMail::FolderJob* ) ),
01770 this, SLOT( slotCheckUidValidityResult( KMail::FolderJob* ) ) );
01771 job->start();
01772 }
01773 }
01774
01775 void KMFolderCachedImap::slotCheckUidValidityResult( KMail::FolderJob* job )
01776 {
01777 if ( job->error() ) {
01778
01779
01780 mSyncState = SYNC_STATE_HANDLE_INBOX;
01781 }
01782 mProgress += 5;
01783 serverSyncInternal();
01784 }
01785
01786 void KMFolderCachedImap::slotPermanentFlags(int flags)
01787 {
01788 mPermanentFlags = flags;
01789 }
01790
01791
01792
01793 void KMFolderCachedImap::listMessages() {
01794 bool groupwareOnly = GlobalSettings::self()->showOnlyGroupwareFoldersForGroupwareAccount()
01795 && GlobalSettings::self()->theIMAPResourceAccount() == (int)mAccount->id()
01796 && folder()->isSystemFolder()
01797 && mImapPath == "/INBOX/";
01798
01799
01800 if( imapPath() == "/" || groupwareOnly ) {
01801 serverSyncInternal();
01802 return;
01803 }
01804
01805 if( !mAccount->slave() ) {
01806 resetSyncState();
01807 emit folderComplete( this, false );
01808 return;
01809 }
01810 uidsOnServer.clear();
01811 uidsOnServer.resize( count() * 2 );
01812 uidsForDeletionOnServer.clear();
01813 mMsgsForDownload.clear();
01814 mUidsForDownload.clear();
01815
01816 mFoundAnIMAPDigest = false;
01817
01818 CachedImapJob* job = new CachedImapJob( FolderJob::tListMessages, this );
01819 connect( job, SIGNAL( result(KMail::FolderJob *) ),
01820 this, SLOT( slotGetLastMessagesResult(KMail::FolderJob *) ) );
01821 job->start();
01822 }
01823
01824 void KMFolderCachedImap::slotGetLastMessagesResult(KMail::FolderJob *job)
01825 {
01826 getMessagesResult(job, true);
01827 }
01828
01829
01830 void KMFolderCachedImap::slotGetMessagesData(KIO::Job * job, const QByteArray & data)
01831 {
01832 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
01833 if ( it == mAccount->jobsEnd() ) {
01834 kdDebug(5006) << "could not find job!?!?!" << endl;
01835
01836
01837
01838 mSyncState = SYNC_STATE_HANDLE_INBOX;
01839 serverSyncInternal();
01840 return;
01841 }
01842 (*it).cdata += QCString(data, data.size() + 1);
01843 int pos = (*it).cdata.find("\r\n--IMAPDIGEST");
01844 if (pos > 0) {
01845 int a = (*it).cdata.find("\r\nX-uidValidity:");
01846 if (a != -1) {
01847 int b = (*it).cdata.find("\r\n", a + 17);
01848 setUidValidity((*it).cdata.mid(a + 17, b - a - 17));
01849 }
01850 a = (*it).cdata.find("\r\nX-Access:");
01851
01852
01853
01854
01855
01856 if (a != -1 && mUserRightsState != KMail::ACLJobs::Ok ) {
01857 int b = (*it).cdata.find("\r\n", a + 12);
01858 const QString access = (*it).cdata.mid(a + 12, b - a - 12);
01859 setReadOnly( access == "Read only" );
01860 }
01861 (*it).cdata.remove(0, pos);
01862 mFoundAnIMAPDigest = true;
01863 }
01864 pos = (*it).cdata.find("\r\n--IMAPDIGEST", 1);
01865
01866 if ( uidsOnServer.size() == 0 )
01867 uidsOnServer.resize( KMail::nextPrime( 2000 ) );
01868 const int v = 42;
01869 while (pos >= 0) {
01870
01871
01872
01873
01874
01875
01876
01877
01878
01879 const QCString& entry( (*it).cdata );
01880 const int indexOfUID = entry.find("X-UID", 16);
01881 const int startOfUIDValue = indexOfUID + 7;
01882 const int indexOfLength = entry.find("X-Length", startOfUIDValue );
01883 const int startOfLengthValue = indexOfLength + 10;
01884 const int indexOfFlags = entry.find("X-Flags", startOfLengthValue );
01885 const int startOfFlagsValue = indexOfFlags + 9;
01886
01887 const int flags = entry.mid( startOfFlagsValue, entry.find( '\r', startOfFlagsValue ) - startOfFlagsValue ).toInt();
01888 const ulong size = entry.mid( startOfLengthValue, entry.find( '\r', startOfLengthValue ) - startOfLengthValue ).toULong();
01889 const ulong uid = entry.mid( startOfUIDValue, entry.find( '\r', startOfUIDValue ) - startOfUIDValue ).toULong();
01890
01891 const bool deleted = ( flags & 8 );
01892 if ( !deleted ) {
01893 if( uid != 0 ) {
01894 if ( uidsOnServer.count() == uidsOnServer.size() ) {
01895 uidsOnServer.resize( KMail::nextPrime( uidsOnServer.size() * 2 ) );
01896
01897 }
01898 uidsOnServer.insert( uid, &v );
01899 }
01900 bool redownload = false;
01901 if ( uid <= lastUid() ) {
01902
01903
01904
01905
01906
01907
01908
01909
01910
01911
01912 KMMsgBase *existingMessage = findByUID(uid);
01913 if( !existingMessage ) {
01914 if ( GlobalSettings::self()->mailLossDebug() ) {
01915 kdDebug(5006) << "Looking at uid " << uid << " high water is: " << lastUid() << " we should delete it" << endl;
01916 }
01917
01918 if ( mDeletedUIDsSinceLastSync.contains(uid) ) {
01919 if ( mUserRightsState != KMail::ACLJobs::Ok || ( mUserRights & KMail::ACLJobs::Delete ) ) {
01920 if ( GlobalSettings::self()->mailLossDebug() ) {
01921 kdDebug(5006) << "message with uid " << uid << " is gone from local cache. Must be deleted on server!!!" << endl;
01922 }
01923 uidsForDeletionOnServer << uid;
01924 } else {
01925 redownload = true;
01926 }
01927 } else {
01928 kdWarning(5006) << "WARNING: ####### " << endl;
01929 kdWarning(5006) << "Message locally missing but not deleted in folder: " << folder()->prettyURL() << endl;
01930 kdWarning(5006) << "The missing UID: " << uid << ". It will be redownloaded " << endl;
01931 redownload = true;
01932 }
01933
01934 } else {
01935
01936
01937
01938 if ( !mReadOnly || !GlobalSettings::allowLocalFlags() ) {
01939
01940 KMFolderImap::flagsToStatus( existingMessage, flags, false, mReadOnly ? INT_MAX : mPermanentFlags );
01941 } else if ( mUserRights & KMail::ACLJobs::WriteSeenFlag ) {
01942 KMFolderImap::seenFlagToStatus( existingMessage, flags );
01943 }
01944 }
01945
01946 }
01947 if ( uid > lastUid() || redownload ) {
01948 if ( GlobalSettings::self()->mailLossDebug() ) {
01949 kdDebug(5006) << "Looking at uid " << uid << " high water is: " << lastUid() << " we should download it" << endl;
01950 }
01951
01952
01953 if ( !uidMap.contains( uid ) ) {
01954 mMsgsForDownload << KMail::CachedImapJob::MsgForDownload(uid, flags, size);
01955 if( imapPath() == "/INBOX/" )
01956 mUidsForDownload << uid;
01957 }
01958
01959 if ( uid > mTentativeHighestUid ) {
01960 if ( GlobalSettings::self()->mailLossDebug() ) {
01961 kdDebug(5006) << "Setting the tentative highest UID to: " << uid << endl;
01962 }
01963 mTentativeHighestUid = uid;
01964 }
01965 }
01966 }
01967 (*it).cdata.remove(0, pos);
01968 (*it).done++;
01969 pos = (*it).cdata.find("\r\n--IMAPDIGEST", 1);
01970 }
01971 }
01972
01973 void KMFolderCachedImap::getMessagesResult( KMail::FolderJob *job, bool lastSet )
01974 {
01975 mProgress += 10;
01976 if ( !job->error() && !mFoundAnIMAPDigest ) {
01977 kdWarning(5006) << "######## Folderlisting did not complete, but there was no error! "
01978 "Aborting sync of folder: " << folder()->prettyURL() << endl;
01979 if ( GlobalSettings::self()->mailLossDebug() ) {
01980 kmkernel->emergencyExit( i18n("Folder listing failed in interesting ways." ) );
01981 }
01982 }
01983 if( job->error() ) {
01984 mContentState = imapNoInformation;
01985 mSyncState = SYNC_STATE_HANDLE_INBOX;
01986 } else {
01987 if( lastSet ) {
01988 mContentState = imapFinished;
01989 mUIDsOfLocallyChangedStatuses.clear();
01990 mStatusChangedLocally = false;
01991 }
01992 }
01993 serverSyncInternal();
01994 }
01995
01996 void KMFolderCachedImap::slotProgress(unsigned long done, unsigned long total)
01997 {
01998 int progressSpan = 100 - 5 - mProgress;
01999 int additionalProgress = ( total == 0 ) ?
02000 progressSpan :
02001 ( progressSpan * done ) / total;
02002
02003
02004
02005 newState( mProgress + additionalProgress, QString::null );
02006 }
02007
02008 void KMFolderCachedImap::setAccount(KMAcctCachedImap *aAccount)
02009 {
02010 assert( aAccount->isA("KMAcctCachedImap") );
02011 mAccount = aAccount;
02012 if( imapPath()=="/" ) aAccount->setFolder( folder() );
02013
02014
02015 QString newName = mAccount->renamedFolder( imapPath() );
02016 if ( !newName.isEmpty() )
02017 folder()->setLabel( newName );
02018
02019 if( !folder() || !folder()->child() || !folder()->child()->count() ) return;
02020 for( KMFolderNode* node = folder()->child()->first(); node;
02021 node = folder()->child()->next() )
02022 if (!node->isDir())
02023 static_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage())->setAccount(aAccount);
02024 }
02025
02026 void KMFolderCachedImap::listNamespaces()
02027 {
02028 ImapAccountBase::ListType type = ImapAccountBase::List;
02029 if ( mAccount->onlySubscribedFolders() )
02030 type = ImapAccountBase::ListSubscribed;
02031
02032 kdDebug(5006) << "listNamespaces " << mNamespacesToList << endl;
02033 if ( mNamespacesToList.isEmpty() ) {
02034 mSyncState = SYNC_STATE_DELETE_SUBFOLDERS;
02035 mPersonalNamespacesCheckDone = true;
02036
02037 QStringList ns = mAccount->namespaces()[ImapAccountBase::OtherUsersNS];
02038 ns += mAccount->namespaces()[ImapAccountBase::SharedNS];
02039 mNamespacesToCheck = ns.count();
02040 for ( QStringList::Iterator it = ns.begin(); it != ns.end(); ++it )
02041 {
02042 if ( (*it).isEmpty() ) {
02043
02044 --mNamespacesToCheck;
02045 continue;
02046 }
02047 KMail::ListJob* job = new KMail::ListJob( mAccount, type, this, mAccount->addPathToNamespace( *it ) );
02048 job->setHonorLocalSubscription( true );
02049 connect( job, SIGNAL(receivedFolders(const QStringList&, const QStringList&,
02050 const QStringList&, const QStringList&, const ImapAccountBase::jobData&)),
02051 this, SLOT(slotCheckNamespace(const QStringList&, const QStringList&,
02052 const QStringList&, const QStringList&, const ImapAccountBase::jobData&)));
02053 job->start();
02054 }
02055 if ( mNamespacesToCheck == 0 ) {
02056 serverSyncInternal();
02057 }
02058 return;
02059 }
02060 mPersonalNamespacesCheckDone = false;
02061
02062 QString ns = mNamespacesToList.front();
02063 mNamespacesToList.pop_front();
02064
02065 mSyncState = SYNC_STATE_LIST_SUBFOLDERS2;
02066 newState( mProgress, i18n("Retrieving folders for namespace %1").arg(ns));
02067 KMail::ListJob* job = new KMail::ListJob( mAccount, type, this,
02068 mAccount->addPathToNamespace( ns ) );
02069 job->setNamespace( ns );
02070 job->setHonorLocalSubscription( true );
02071 connect( job, SIGNAL(receivedFolders(const QStringList&, const QStringList&,
02072 const QStringList&, const QStringList&, const ImapAccountBase::jobData&)),
02073 this, SLOT(slotListResult(const QStringList&, const QStringList&,
02074 const QStringList&, const QStringList&, const ImapAccountBase::jobData&)));
02075 job->start();
02076 }
02077
02078 void KMFolderCachedImap::slotCheckNamespace( const QStringList& subfolderNames,
02079 const QStringList& subfolderPaths,
02080 const QStringList& subfolderMimeTypes,
02081 const QStringList& subfolderAttributes,
02082 const ImapAccountBase::jobData& jobData )
02083 {
02084 Q_UNUSED( subfolderPaths );
02085 Q_UNUSED( subfolderMimeTypes );
02086 Q_UNUSED( subfolderAttributes );
02087 --mNamespacesToCheck;
02088 kdDebug(5006) << "slotCheckNamespace " << subfolderNames << ",remain=" <<
02089 mNamespacesToCheck << endl;
02090
02091
02092
02093 QString name = jobData.path.mid( 1, jobData.path.length()-2 );
02094 name.remove( mAccount->delimiterForNamespace( name ) );
02095 if ( name.isEmpty() ) {
02096
02097 kdWarning(5006) << "slotCheckNamespace: ignoring empty folder!" << endl;
02098 return;
02099 }
02100
02101 folder()->createChildFolder();
02102 KMFolderNode *node = 0;
02103 for ( node = folder()->child()->first(); node;
02104 node = folder()->child()->next())
02105 {
02106 if ( !node->isDir() && node->name() == name )
02107 break;
02108 }
02109 if ( !subfolderNames.isEmpty() ) {
02110 if ( node ) {
02111
02112 kdDebug(5006) << "found namespace folder " << name << endl;
02113 } else
02114 {
02115
02116 kdDebug(5006) << "create namespace folder " << name << endl;
02117 KMFolder* newFolder = folder()->child()->createFolder( name, false,
02118 KMFolderTypeCachedImap );
02119 if ( newFolder ) {
02120 KMFolderCachedImap *f = static_cast<KMFolderCachedImap*>( newFolder->storage() );
02121 f->setImapPath( mAccount->addPathToNamespace( name ) );
02122 f->setNoContent( true );
02123 f->setAccount( mAccount );
02124 f->close("cachedimap");
02125 kmkernel->dimapFolderMgr()->contentsChanged();
02126 }
02127 }
02128 } else {
02129 if ( node ) {
02130 kdDebug(5006) << "delete namespace folder " << name << endl;
02131 KMFolder* fld = static_cast<KMFolder*>(node);
02132 kmkernel->dimapFolderMgr()->remove( fld );
02133 }
02134 }
02135
02136 if ( mNamespacesToCheck == 0 ) {
02137
02138 serverSyncInternal();
02139 }
02140 }
02141
02142
02143
02144 bool KMFolderCachedImap::listDirectory()
02145 {
02146 if( !mAccount->slave() ) {
02147 resetSyncState();
02148 emit folderComplete( this, false );
02149 return false;
02150 }
02151 mSubfolderState = imapInProgress;
02152
02153
02154 ImapAccountBase::ListType type = ImapAccountBase::List;
02155 if ( mAccount->onlySubscribedFolders() )
02156 type = ImapAccountBase::ListSubscribed;
02157 KMail::ListJob* job = new KMail::ListJob( mAccount, type, this );
02158 job->setHonorLocalSubscription( true );
02159 connect( job, SIGNAL(receivedFolders(const QStringList&, const QStringList&,
02160 const QStringList&, const QStringList&, const ImapAccountBase::jobData&)),
02161 this, SLOT(slotListResult(const QStringList&, const QStringList&,
02162 const QStringList&, const QStringList&, const ImapAccountBase::jobData&)));
02163 job->start();
02164
02165 return true;
02166 }
02167
02168 void KMFolderCachedImap::slotListResult( const QStringList& folderNames,
02169 const QStringList& folderPaths,
02170 const QStringList& folderMimeTypes,
02171 const QStringList& folderAttributes,
02172 const ImapAccountBase::jobData& jobData )
02173 {
02174 Q_UNUSED( jobData );
02175
02176
02177 mSubfolderNames = folderNames;
02178 mSubfolderPaths = folderPaths;
02179 mSubfolderMimeTypes = folderMimeTypes;
02180 mSubfolderState = imapFinished;
02181 mSubfolderAttributes = folderAttributes;
02182
02183
02184 folder()->createChildFolder();
02185 KMFolderNode *node = folder()->child()->first();
02186 bool root = ( this == mAccount->rootFolder() );
02187
02188 QPtrList<KMFolder> toRemove;
02189 bool emptyList = ( root && mSubfolderNames.empty() );
02190 if ( !emptyList ) {
02191 while (node) {
02192 if (!node->isDir() ) {
02193 KMFolderCachedImap *f = static_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage());
02194
02195 if ( mSubfolderNames.findIndex(node->name()) == -1 ) {
02196 QString name = node->name();
02197
02198
02199 bool isInNamespace = ( jobData.curNamespace.isEmpty() ||
02200 jobData.curNamespace == mAccount->namespaceForFolder( f ) );
02201
02202 bool ignore = root && ( f->imapPath() == "/INBOX/" ||
02203 mAccount->isNamespaceFolder( name ) || !isInNamespace );
02204
02205
02206 if( !f->imapPath().isEmpty() && !ignore ) {
02207
02208
02209 toRemove.append( f->folder() );
02210 kdDebug(5006) << node->name() << " isn't on the server. It has an imapPath -> delete it locally" << endl;
02211 }
02212 } else {
02213
02214
02218 int index = mSubfolderNames.findIndex( node->name() );
02219 f->mFolderAttributes = folderAttributes[ index ];
02220 }
02221 } else {
02222
02223 }
02224 node = folder()->child()->next();
02225 }
02226 }
02227
02228 QPtrListIterator<KMFolder> jt( toRemove );
02229 KMFolder *doomed;
02230 while ( ( doomed = jt.current() ) != 0 ) {
02231 ++jt;
02232 if ( doomed ) {
02233 rescueUnsyncedMessagesAndDeleteFolder( doomed );
02234 }
02235 }
02236
02237 mProgress += 5;
02238
02239
02240 slotRescueDone( 0 );
02241 }
02242
02243
02244 void KMFolderCachedImap::listDirectory2()
02245 {
02246 QString path = folder()->path();
02247 kmkernel->dimapFolderMgr()->quiet(true);
02248
02249 bool root = ( this == mAccount->rootFolder() );
02250 if ( root && !mAccount->hasInbox() )
02251 {
02252 KMFolderCachedImap *f = 0;
02253 KMFolderNode *node;
02254
02255 for (node = folder()->child()->first(); node; node = folder()->child()->next())
02256 if (!node->isDir() && node->name() == "INBOX") break;
02257 if (node) {
02258 f = static_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage());
02259 } else {
02260 KMFolder* newFolder = folder()->child()->createFolder("INBOX", true, KMFolderTypeCachedImap);
02261 if ( newFolder ) {
02262 f = static_cast<KMFolderCachedImap*>(newFolder->storage());
02263 }
02264 }
02265 if ( f ) {
02266 f->setAccount( mAccount );
02267 f->setImapPath( "/INBOX/" );
02268 f->folder()->setLabel( i18n("inbox") );
02269 }
02270 if (!node) {
02271 if ( f )
02272 f->close("cachedimap");
02273 kmkernel->dimapFolderMgr()->contentsChanged();
02274 }
02275
02276 mAccount->setHasInbox( true );
02277 }
02278
02279 if ( root && !mSubfolderNames.isEmpty() ) {
02280 KMFolderCachedImap* parent =
02281 findParent( mSubfolderPaths.first(), mSubfolderNames.first() );
02282 if ( parent ) {
02283 kdDebug(5006) << "KMFolderCachedImap::listDirectory2 - pass listing to "
02284 << parent->label() << endl;
02285 mSubfolderNames.clear();
02286 }
02287 }
02288
02289
02290 QValueVector<int> foldersNewOnServer;
02291 for (uint i = 0; i < mSubfolderNames.count(); i++) {
02292
02293
02294 KMFolderCachedImap *f = 0;
02295 KMFolderNode *node = 0;
02296 for (node = folder()->child()->first(); node;
02297 node = folder()->child()->next())
02298 if (!node->isDir() && node->name() == mSubfolderNames[i]) break;
02299
02300 if (!node) {
02301
02302
02303 QString subfolderPath = mSubfolderPaths[i];
02304
02305
02306
02307 bool locallyDeleted = mAccount->isDeletedFolder( subfolderPath );
02308
02309
02310
02311 if ( !locallyDeleted && mAccount->isPreviouslyDeletedFolder( subfolderPath ) ) {
02312 locallyDeleted = KMessageBox::warningYesNo(
02313 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;
02314 }
02315
02316 if ( locallyDeleted ) {
02317 kdDebug(5006) << subfolderPath << " was deleted locally => delete on server." << endl;
02318 foldersForDeletionOnServer += mAccount->deletedFolderPaths( subfolderPath );
02319 } else {
02320 kdDebug(5006) << subfolderPath << " is a new folder on the server => create local cache" << endl;
02321 foldersNewOnServer.append( i );
02322 }
02323 } else {
02324 if( static_cast<KMFolder*>(node)->folderType() == KMFolderTypeCachedImap )
02325 f = dynamic_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage());
02326 if( f ) {
02327
02328
02329
02330 f->setAccount(mAccount);
02331 f->setNoContent(mSubfolderMimeTypes[i] == "inode/directory");
02332 f->setNoChildren(mSubfolderMimeTypes[i] == "message/digest");
02333 f->setImapPath(mSubfolderPaths[i]);
02334 }
02335 }
02336 }
02337
02338
02339
02340
02341
02342
02343
02344
02345
02346
02347
02348 if ( GlobalSettings::self()->showOnlyGroupwareFoldersForGroupwareAccount()
02349 && GlobalSettings::self()->theIMAPResourceAccount() == (int)mAccount->id()
02350 && mAccount->hasAnnotationSupport()
02351 && GlobalSettings::self()->theIMAPResourceEnabled()
02352 && !foldersNewOnServer.isEmpty() ) {
02353
02354 QStringList paths;
02355 for ( uint i = 0; i < foldersNewOnServer.count(); ++i )
02356 paths << mSubfolderPaths[ foldersNewOnServer[i] ];
02357
02358 AnnotationJobs::MultiUrlGetAnnotationJob* job =
02359 AnnotationJobs::multiUrlGetAnnotation( mAccount->slave(), mAccount->getUrl(), paths, KOLAB_FOLDERTYPE );
02360 ImapAccountBase::jobData jd( QString::null, folder() );
02361 jd.cancellable = true;
02362 mAccount->insertJob(job, jd);
02363 connect( job, SIGNAL(result(KIO::Job *)),
02364 SLOT(slotMultiUrlGetAnnotationResult(KIO::Job *)) );
02365
02366 } else {
02367 createFoldersNewOnServerAndFinishListing( foldersNewOnServer );
02368 }
02369 }
02370
02371 void KMFolderCachedImap::createFoldersNewOnServerAndFinishListing( const QValueVector<int> foldersNewOnServer )
02372 {
02373 for ( uint i = 0; i < foldersNewOnServer.count(); ++i ) {
02374 int idx = foldersNewOnServer[i];
02375 KMFolder* newFolder = folder()->child()->createFolder( mSubfolderNames[idx], false, KMFolderTypeCachedImap);
02376 if (newFolder) {
02377 KMFolderCachedImap *f = dynamic_cast<KMFolderCachedImap*>(newFolder->storage());
02378 kdDebug(5006) << " ####### Locally creating folder " << mSubfolderNames[idx] <<endl;
02379 f->close("cachedimap");
02380 f->setAccount(mAccount);
02381 f->mAnnotationFolderType = "FROMSERVER";
02382 f->setNoContent(mSubfolderMimeTypes[idx] == "inode/directory");
02383 f->setNoChildren(mSubfolderMimeTypes[idx] == "message/digest");
02384 f->setImapPath(mSubfolderPaths[idx]);
02385 f->mFolderAttributes = mSubfolderAttributes[idx];
02386 mNewlyCreatedSubfolders.append( QGuardedPtr<KMFolderCachedImap>( f ) );
02387 kdDebug(5006) << " ####### Attributes: " << f->mFolderAttributes <<endl;
02388
02389 kmkernel->dimapFolderMgr()->contentsChanged();
02390 } else {
02391 kdDebug(5006) << "can't create folder " << mSubfolderNames[idx] <<endl;
02392 }
02393 }
02394
02395 kmkernel->dimapFolderMgr()->quiet(false);
02396 emit listComplete(this);
02397 if ( !mPersonalNamespacesCheckDone ) {
02398
02399 mSyncState = SYNC_STATE_LIST_NAMESPACES;
02400 }
02401 serverSyncInternal();
02402 }
02403
02404
02405 KMFolderCachedImap* KMFolderCachedImap::findParent( const QString& path,
02406 const QString& name )
02407 {
02408 QString parent = path.left( path.length() - name.length() - 2 );
02409 if ( parent.length() > 1 )
02410 {
02411
02412 parent = parent.right( parent.length() - 1 );
02413 if ( parent != label() )
02414 {
02415 KMFolderNode *node = folder()->child()->first();
02416
02417 while ( node )
02418 {
02419 if ( node->name() == parent )
02420 {
02421 KMFolder* fld = static_cast<KMFolder*>(node);
02422 KMFolderCachedImap* imapFld =
02423 static_cast<KMFolderCachedImap*>( fld->storage() );
02424 return imapFld;
02425 }
02426 node = folder()->child()->next();
02427 }
02428 }
02429 }
02430 return 0;
02431 }
02432
02433 void KMFolderCachedImap::slotSubFolderComplete(KMFolderCachedImap* sub, bool success)
02434 {
02435 Q_UNUSED(sub);
02436
02437 if ( success ) {
02438 serverSyncInternal();
02439 }
02440 else
02441 {
02442
02443 if ( mCurrentSubfolder ) {
02444 Q_ASSERT( sub == mCurrentSubfolder );
02445 disconnectSubFolderSignals();
02446 }
02447
02448
02449
02450 mSubfoldersForSync.clear();
02451 mSyncState = SYNC_STATE_INITIAL;
02452 close("cachedimap");
02453 emit syncStateChanged();
02454 emit folderComplete( this, false );
02455 }
02456 }
02457
02458 void KMFolderCachedImap::slotSubFolderCloseToQuotaChanged()
02459 {
02460 if ( !mQuotaOnly ) {
02461 mSomeSubFolderCloseToQuotaChanged = true;
02462 }
02463 }
02464
02465 void KMFolderCachedImap::slotSimpleData(KIO::Job * job, const QByteArray & data)
02466 {
02467 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
02468 if (it == mAccount->jobsEnd()) return;
02469 QBuffer buff((*it).data);
02470 buff.open(IO_WriteOnly | IO_Append);
02471 buff.writeBlock(data.data(), data.size());
02472 buff.close();
02473 }
02474
02475 FolderJob*
02476 KMFolderCachedImap::doCreateJob( KMMessage *msg, FolderJob::JobType jt, KMFolder *folder,
02477 QString, const AttachmentStrategy* ) const
02478 {
02479 QPtrList<KMMessage> msgList;
02480 msgList.append( msg );
02481 CachedImapJob *job = new CachedImapJob( msgList, jt, folder? static_cast<KMFolderCachedImap*>( folder->storage() ):0 );
02482 job->setParentFolder( this );
02483 return job;
02484 }
02485
02486 FolderJob*
02487 KMFolderCachedImap::doCreateJob( QPtrList<KMMessage>& msgList, const QString& sets,
02488 FolderJob::JobType jt, KMFolder *folder ) const
02489 {
02490
02491 Q_UNUSED( sets );
02492 CachedImapJob *job = new CachedImapJob( msgList, jt, folder? static_cast<KMFolderCachedImap*>( folder->storage() ):0 );
02493 job->setParentFolder( this );
02494 return job;
02495 }
02496
02497 void
02498 KMFolderCachedImap::setUserRights( unsigned int userRights, KMail::ACLJobs::ACLFetchState state )
02499 {
02500 mUserRights = userRights;
02501 mUserRightsState = state;
02502 writeConfigKeysWhichShouldNotGetOverwrittenByReadConfig();
02503 }
02504
02505 void
02506 KMFolderCachedImap::slotReceivedUserRights( KMFolder* folder )
02507 {
02508 if ( folder->storage() == this ) {
02509 disconnect( mAccount, SIGNAL( receivedUserRights( KMFolder* ) ),
02510 this, SLOT( slotReceivedUserRights( KMFolder* ) ) );
02511 if ( mUserRightsState == KMail::ACLJobs::Ok ) {
02512 setReadOnly( ( mUserRights & KMail::ACLJobs::Insert ) == 0 );
02513 }
02514 mProgress += 5;
02515 serverSyncInternal();
02516 }
02517 }
02518
02519 void
02520 KMFolderCachedImap::setReadOnly( bool readOnly )
02521 {
02522 if ( readOnly != mReadOnly ) {
02523 mReadOnly = readOnly;
02524 emit readOnlyChanged( folder() );
02525 }
02526 }
02527
02528 void
02529 KMFolderCachedImap::slotReceivedACL( KMFolder* folder, KIO::Job* job, const KMail::ACLList& aclList )
02530 {
02531 if ( folder->storage() == this ) {
02532 disconnect( mAccount, SIGNAL(receivedACL( KMFolder*, KIO::Job*, const KMail::ACLList& )),
02533 this, SLOT(slotReceivedACL( KMFolder*, KIO::Job*, const KMail::ACLList& )) );
02534 mACLListState = job->error() ? KMail::ACLJobs::FetchFailed : KMail::ACLJobs::Ok;
02535 mACLList = aclList;
02536 serverSyncInternal();
02537 }
02538 }
02539
02540 void
02541 KMFolderCachedImap::slotStorageQuotaResult( const QuotaInfo& info )
02542 {
02543 setQuotaInfo( info );
02544 }
02545
02546 void KMFolderCachedImap::setQuotaInfo( const QuotaInfo & info )
02547 {
02548 if ( info != mQuotaInfo ) {
02549 const bool wasCloseToQuota = isCloseToQuota();
02550 mQuotaInfo = info;
02551 writeConfigKeysWhichShouldNotGetOverwrittenByReadConfig();
02552 if ( wasCloseToQuota != isCloseToQuota() ) {
02553 emit closeToQuotaChanged();
02554 }
02555 emit folderSizeChanged();
02556 }
02557 }
02558
02559 void
02560 KMFolderCachedImap::setACLList( const ACLList& arr )
02561 {
02562 mACLList = arr;
02563 mACLListState = KMail::ACLJobs::Ok;
02564 }
02565
02566 void
02567 KMFolderCachedImap::slotMultiSetACLResult(KIO::Job *job)
02568 {
02569 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
02570 if ( it == mAccount->jobsEnd() ) return;
02571 if ( (*it).parent != folder() ) return;
02572
02573 if ( job->error() )
02574
02575
02576 job->showErrorDialog();
02577 else
02578 kmkernel->iCalIface().addFolderChange( folder(), KMailICalIfaceImpl::ACL );
02579
02580 if (mAccount->slave()) mAccount->removeJob(job);
02581 serverSyncInternal();
02582 }
02583
02584 void
02585 KMFolderCachedImap::slotACLChanged( const QString& userId, int permissions )
02586 {
02587
02588
02589 for( ACLList::Iterator it = mACLList.begin(); it != mACLList.end(); ++it ) {
02590 if ( (*it).userId == userId && (*it).permissions == permissions ) {
02591 if ( permissions == -1 )
02592 mACLList.erase( it );
02593 else
02594 (*it).changed = false;
02595 return;
02596 }
02597 }
02598 }
02599
02600
02601 void KMFolderCachedImap::resetSyncState()
02602 {
02603 if ( mSyncState == SYNC_STATE_INITIAL ) return;
02604 mSubfoldersForSync.clear();
02605 mNewlyCreatedSubfolders.clear();
02606 mSyncState = SYNC_STATE_INITIAL;
02607 close("cachedimap");
02608
02609 KPIM::ProgressItem *progressItem = mAccount->mailCheckProgressItem();
02610 QString str = i18n("Aborted");
02611 if (progressItem)
02612 progressItem->setStatus( str );
02613 emit statusMsg( str );
02614 emit syncStateChanged();
02615 }
02616
02617 void KMFolderCachedImap::slotIncreaseProgress()
02618 {
02619 mProgress += 5;
02620 }
02621
02622 void KMFolderCachedImap::newState( int progress, const QString& syncStatus )
02623 {
02624
02625 KPIM::ProgressItem *progressItem = mAccount->mailCheckProgressItem();
02626 if( progressItem )
02627 progressItem->setCompletedItems( progress );
02628 if ( !syncStatus.isEmpty() ) {
02629 QString str;
02630
02631 if ( mAccount->imapFolder() == this )
02632 str = syncStatus;
02633 else
02634 str = QString( "%1: %2" ).arg( label() ).arg( syncStatus );
02635 if( progressItem )
02636 progressItem->setStatus( str );
02637 emit statusMsg( str );
02638 }
02639 if( progressItem )
02640 progressItem->updateProgress();
02641 }
02642
02643 void KMFolderCachedImap::setSubfolderState( imapState state )
02644 {
02645 mSubfolderState = state;
02646 if ( state == imapNoInformation && folder()->child() )
02647 {
02648
02649 KMFolderNode* node;
02650 QPtrListIterator<KMFolderNode> it( *folder()->child() );
02651 for ( ; (node = it.current()); )
02652 {
02653 ++it;
02654 if (node->isDir()) continue;
02655 KMFolder *folder = static_cast<KMFolder*>(node);
02656 static_cast<KMFolderCachedImap*>(folder->storage())->setSubfolderState( state );
02657 }
02658 }
02659 }
02660
02661 void KMFolderCachedImap::setImapPath(const QString &path)
02662 {
02663 mImapPath = path;
02664 }
02665
02666 static bool isFolderTypeKnownToUs( const QString &type )
02667 {
02668 for ( uint i = 0 ; i <= ContentsTypeLast; ++i ) {
02669 FolderContentsType contentsType = static_cast<KMail::FolderContentsType>( i );
02670 if ( type == KMailICalIfaceImpl::annotationForContentsType( contentsType ) )
02671 return true;
02672 }
02673 return false;
02674 }
02675
02676
02677
02678
02679
02680
02681 void KMFolderCachedImap::updateAnnotationFolderType()
02682 {
02683 QString oldType = mAnnotationFolderType;
02684 QString oldSubType;
02685 int dot = oldType.find( '.' );
02686 if ( dot != -1 ) {
02687 oldType.truncate( dot );
02688 oldSubType = mAnnotationFolderType.mid( dot + 1 );
02689 }
02690
02691 QString newType, newSubType;
02692
02693 if ( kmkernel->iCalIface().storageFormat( folder() ) == KMailICalIfaceImpl::StorageXML ) {
02694 newType = KMailICalIfaceImpl::annotationForContentsType( mContentsType );
02695 if ( kmkernel->iCalIface().isStandardResourceFolder( folder() ) )
02696 newSubType = "default";
02697 else if ( oldSubType != "default" )
02698 newSubType = oldSubType;
02699 }
02700
02701
02702
02703
02704 const bool changingTypeAllowed = isFolderTypeKnownToUs( oldType ) ||
02705 ( mContentsType != ContentsTypeMail );
02706
02707
02708 if ( ( newType != oldType || newSubType != oldSubType ) && changingTypeAllowed ) {
02709 mAnnotationFolderType = newType + ( newSubType.isEmpty() ? QString::null : "."+newSubType );
02710 mAnnotationFolderTypeChanged = true;
02711 kdDebug(5006) << mImapPath << ": updateAnnotationFolderType: '" << mAnnotationFolderType << "', was (" << oldType << " " << oldSubType << ") => mAnnotationFolderTypeChanged set to TRUE" << endl;
02712 }
02713
02714 writeConfigKeysWhichShouldNotGetOverwrittenByReadConfig();
02715 }
02716
02717 void KMFolderCachedImap::setIncidencesFor( IncidencesFor incfor )
02718 {
02719 if ( mIncidencesFor != incfor ) {
02720 mIncidencesFor = incfor;
02721 mIncidencesForChanged = true;
02722 }
02723 }
02724
02725 void KMFolderCachedImap::setSharedSeenFlags(bool b)
02726 {
02727 if ( mSharedSeenFlags != b ) {
02728 mSharedSeenFlags = b;
02729 mSharedSeenFlagsChanged = true;
02730 }
02731 }
02732
02733 void KMFolderCachedImap::slotAnnotationResult(const QString& entry, const QString& value, bool found)
02734 {
02735 if ( entry == KOLAB_FOLDERTYPE ) {
02736
02737
02738
02739
02740
02741 if ( found ) {
02742 QString type = value;
02743 QString subtype;
02744 int dot = value.find( '.' );
02745 if ( dot != -1 ) {
02746 type.truncate( dot );
02747 subtype = value.mid( dot + 1 );
02748 }
02749 bool foundKnownType = false;
02750 for ( uint i = 0 ; i <= ContentsTypeLast; ++i ) {
02751 FolderContentsType contentsType = static_cast<KMail::FolderContentsType>( i );
02752 if ( type == KMailICalIfaceImpl::annotationForContentsType( contentsType ) ) {
02753
02754
02755 if ( contentsType != ContentsTypeMail )
02756 kmkernel->iCalIface().setStorageFormat( folder(), KMailICalIfaceImpl::StorageXML );
02757 mAnnotationFolderType = value;
02758 if ( folder()->parent()->owner()->idString() != GlobalSettings::self()->theIMAPResourceFolderParent()
02759 && GlobalSettings::self()->theIMAPResourceEnabled()
02760 && subtype == "default" ) {
02761
02762
02763 mAnnotationFolderType = type;
02764 kdDebug(5006) << mImapPath << ": slotGetAnnotationResult: parent folder is " << folder()->parent()->owner()->idString() << " => truncating annotation to " << value << endl;
02765 }
02766 setContentsType( contentsType );
02767 mAnnotationFolderTypeChanged = false;
02768 foundKnownType = true;
02769
02770
02771
02772
02773
02774 if ( contentsType != ContentsTypeMail )
02775 markUnreadAsRead();
02776
02777 break;
02778 }
02779 }
02780 if ( !foundKnownType ) {
02781
02782
02783
02784
02785 mAnnotationFolderTypeChanged = false;
02786 mAnnotationFolderType = value;
02787 setContentsType( ContentsTypeMail );
02788 }
02789
02790
02791 writeConfigKeysWhichShouldNotGetOverwrittenByReadConfig();
02792
02793 }
02794 else if ( !mReadOnly ) {
02795
02796
02797 mAnnotationFolderTypeChanged = true;
02798 }
02799 } else if ( entry == KOLAB_INCIDENCESFOR ) {
02800 if ( found ) {
02801 mIncidencesFor = incidencesForFromString( value );
02802 Q_ASSERT( mIncidencesForChanged == false );
02803 }
02804 } else if ( entry == KOLAB_SHAREDSEEN ) {
02805 if ( found ) {
02806 mSharedSeenFlags = value == "true";
02807 }
02808 }
02809 }
02810
02811 void KMFolderCachedImap::slotGetAnnotationResult( KIO::Job* job )
02812 {
02813 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
02814 Q_ASSERT( it != mAccount->jobsEnd() );
02815 if ( it == mAccount->jobsEnd() ) return;
02816 Q_ASSERT( (*it).parent == folder() );
02817 if ( (*it).parent != folder() ) return;
02818
02819 AnnotationJobs::GetAnnotationJob* annjob = static_cast<AnnotationJobs::GetAnnotationJob *>( job );
02820 if ( annjob->error() ) {
02821 if ( job->error() == KIO::ERR_UNSUPPORTED_ACTION ) {
02822
02823 if ( GlobalSettings::self()->theIMAPResourceStorageFormat() == GlobalSettings::EnumTheIMAPResourceStorageFormat::XML
02824 && (uint)GlobalSettings::self()->theIMAPResourceAccount() == mAccount->id() )
02825 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() ) );
02826 mAccount->setHasNoAnnotationSupport();
02827 }
02828 else
02829 kdWarning(5006) << "slotGetAnnotationResult: " << job->errorString() << endl;
02830 }
02831
02832 if (mAccount->slave()) mAccount->removeJob(job);
02833 mProgress += 2;
02834 serverSyncInternal();
02835 }
02836
02837 void KMFolderCachedImap::slotMultiUrlGetAnnotationResult( KIO::Job* job )
02838 {
02839 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
02840 Q_ASSERT( it != mAccount->jobsEnd() );
02841 if ( it == mAccount->jobsEnd() ) return;
02842 Q_ASSERT( (*it).parent == folder() );
02843 if ( (*it).parent != folder() ) return;
02844
02845 QValueVector<int> folders;
02846 AnnotationJobs::MultiUrlGetAnnotationJob* annjob
02847 = static_cast<AnnotationJobs::MultiUrlGetAnnotationJob *>( job );
02848 if ( annjob->error() ) {
02849 if ( job->error() == KIO::ERR_UNSUPPORTED_ACTION ) {
02850
02851 if ( GlobalSettings::self()->theIMAPResourceStorageFormat() == GlobalSettings::EnumTheIMAPResourceStorageFormat::XML
02852 && (uint)GlobalSettings::self()->theIMAPResourceAccount() == mAccount->id() )
02853 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() ) );
02854 mAccount->setHasNoAnnotationSupport();
02855 }
02856 else
02857 kdWarning(5006) << "slotGetMultiUrlAnnotationResult: " << job->errorString() << endl;
02858 } else {
02859
02860 QMap<QString, QString> annotations = annjob->annotations();
02861 QMap<QString, QString>::Iterator it = annotations.begin();
02862 for ( ; it != annotations.end(); ++it ) {
02863 const QString folderPath = it.key();
02864 const QString annotation = it.data();
02865 kdDebug(5006) << k_funcinfo << "Folder: " << folderPath << " has type: " << annotation << endl;
02866
02867 QString type(annotation);
02868 int dot = annotation.find( '.' );
02869 if ( dot != -1 ) type.truncate( dot );
02870 type = type.simplifyWhiteSpace();
02871
02872 const int idx = mSubfolderPaths.findIndex( folderPath );
02873 const bool isNoContent = mSubfolderMimeTypes[idx] == "inode/directory";
02874 if ( ( isNoContent && type.isEmpty() )
02875 || ( !type.isEmpty() && type != KMailICalIfaceImpl::annotationForContentsType( ContentsTypeMail ) ) ) {
02876 folders.append( idx );
02877 kdDebug(5006) << k_funcinfo << " subscribing to: " << folderPath << endl;
02878 } else {
02879 kdDebug(5006) << k_funcinfo << " automatically unsubscribing from: " << folderPath << endl;
02880 mAccount->changeLocalSubscription( folderPath, false );
02881 }
02882 }
02883 }
02884
02885 if (mAccount->slave()) mAccount->removeJob(job);
02886 createFoldersNewOnServerAndFinishListing( folders );
02887 }
02888
02889 void KMFolderCachedImap::slotQuotaResult( KIO::Job* job )
02890 {
02891 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
02892 Q_ASSERT( it != mAccount->jobsEnd() );
02893 if ( it == mAccount->jobsEnd() ) return;
02894 Q_ASSERT( (*it).parent == folder() );
02895 if ( (*it).parent != folder() ) return;
02896
02897 QuotaJobs::GetStorageQuotaJob* quotajob = static_cast<QuotaJobs::GetStorageQuotaJob *>( job );
02898 QuotaInfo empty;
02899 if ( quotajob->error() ) {
02900 if ( job->error() == KIO::ERR_UNSUPPORTED_ACTION ) {
02901
02902 mAccount->setHasNoQuotaSupport();
02903 setQuotaInfo( empty );
02904 }
02905 else
02906 kdWarning(5006) << "slotGetQuotaResult: " << job->errorString() << endl;
02907 }
02908
02909 if (mAccount->slave()) mAccount->removeJob(job);
02910 mProgress += 2;
02911 serverSyncInternal();
02912 }
02913
02914 void
02915 KMFolderCachedImap::slotAnnotationChanged( const QString& entry, const QString& attribute, const QString& value )
02916 {
02917 Q_UNUSED( attribute );
02918 Q_UNUSED( value );
02919
02920 if ( entry == KOLAB_FOLDERTYPE )
02921 mAnnotationFolderTypeChanged = false;
02922 else if ( entry == KOLAB_INCIDENCESFOR ) {
02923 mIncidencesForChanged = false;
02924
02925
02926 kmkernel->iCalIface().addFolderChange( folder(), KMailICalIfaceImpl::ACL );
02927 } else if ( entry == KOLAB_SHAREDSEEN ) {
02928 mSharedSeenFlagsChanged = false;
02929 }
02930 }
02931
02932 void KMFolderCachedImap::slotTestAnnotationResult(KIO::Job *job)
02933 {
02934 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
02935 Q_ASSERT( it != mAccount->jobsEnd() );
02936 if ( it == mAccount->jobsEnd() ) return;
02937 Q_ASSERT( (*it).parent == folder() );
02938 if ( (*it).parent != folder() ) return;
02939
02940 mAccount->setAnnotationCheckPassed( true );
02941 if ( job->error() ) {
02942 kdDebug(5006) << "Test Annotation was not passed, disabling annotation support" << endl;
02943 mAccount->setHasNoAnnotationSupport( );
02944 } else {
02945 kdDebug(5006) << "Test Annotation was passed OK" << endl;
02946 }
02947 if (mAccount->slave()) mAccount->removeJob(job);
02948 serverSyncInternal();
02949 }
02950
02951 void
02952 KMFolderCachedImap::slotSetAnnotationResult(KIO::Job *job)
02953 {
02954 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
02955 if ( it == mAccount->jobsEnd() ) return;
02956 if ( (*it).parent != folder() ) return;
02957
02958 bool cont = true;
02959 if ( job->error() ) {
02960
02961 if ( job->error() == KIO::ERR_UNSUPPORTED_ACTION && contentsType() == ContentsTypeMail ) {
02962 if (mAccount->slave()) mAccount->removeJob(job);
02963 } else {
02964 cont = mAccount->handleJobError( job, i18n( "Error while setting annotation: " ) + '\n' );
02965 }
02966 } else {
02967 if (mAccount->slave()) mAccount->removeJob(job);
02968 }
02969 if ( cont )
02970 serverSyncInternal();
02971 }
02972
02973 void KMFolderCachedImap::slotUpdateLastUid()
02974 {
02975 if( mTentativeHighestUid != 0 ) {
02976
02977
02978
02979
02980
02981
02982
02983
02984
02985
02986
02987 bool sane = count() == 0;
02988
02989 for (int i=0;i<count(); i++ ) {
02990 ulong uid = getMsgBase(i)->UID();
02991 if ( uid > mTentativeHighestUid && uid > lastUid() ) {
02992 kdWarning(5006) << "DANGER: Either the server listed a wrong highest uid, "
02993 "or we parsed it wrong. Send email to adam@kde.org, please, and include this log." << endl;
02994 kdWarning(5006) << "uid: " << uid << " mTentativeHighestUid: " << mTentativeHighestUid << endl;
02995 assert( false );
02996 break;
02997 } else {
02998 sane = true;
02999 }
03000 }
03001 if (sane) {
03002 if ( GlobalSettings::self()->mailLossDebug() ) {
03003 kdDebug(5006) << "Tentative highest UID test was sane, writing out: " << mTentativeHighestUid << endl;
03004 }
03005 setLastUid( mTentativeHighestUid );
03006 }
03007 }
03008 mTentativeHighestUid = 0;
03009 }
03010
03011 bool KMFolderCachedImap::isMoveable() const
03012 {
03013 return ( hasChildren() == HasNoChildren &&
03014 !folder()->isSystemFolder() ) ? true : false;
03015 }
03016
03017 void KMFolderCachedImap::slotFolderDeletionOnServerFinished()
03018 {
03019 for ( QStringList::const_iterator it = foldersForDeletionOnServer.constBegin();
03020 it != foldersForDeletionOnServer.constEnd(); ++it ) {
03021 KURL url( mAccount->getUrl() );
03022 url.setPath( *it );
03023 kmkernel->iCalIface().folderDeletedOnServer( url );
03024 }
03025 serverSyncInternal();
03026 }
03027
03028 int KMFolderCachedImap::createIndexFromContentsRecursive()
03029 {
03030 if ( !folder() || !folder()->child() )
03031 return 0;
03032
03033 KMFolderNode *node = 0;
03034 for( QPtrListIterator<KMFolderNode> it( *folder()->child() ); (node = it.current()); ++it ) {
03035 if( !node->isDir() ) {
03036 KMFolderCachedImap* storage = static_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage());
03037 kdDebug() << k_funcinfo << "Re-indexing: " << storage->folder()->label() << endl;
03038 int rv = storage->createIndexFromContentsRecursive();
03039 if ( rv > 0 )
03040 return rv;
03041 }
03042 }
03043
03044 return createIndexFromContents();
03045 }
03046
03047 void KMFolderCachedImap::setAlarmsBlocked( bool blocked )
03048 {
03049 mAlarmsBlocked = blocked;
03050 }
03051
03052 bool KMFolderCachedImap::alarmsBlocked() const
03053 {
03054 return mAlarmsBlocked;
03055 }
03056
03057 bool KMFolderCachedImap::isCloseToQuota() const
03058 {
03059 bool closeToQuota = false;
03060 if ( mQuotaInfo.isValid() && mQuotaInfo.max().toInt() > 0 ) {
03061 const int ratio = mQuotaInfo.current().toInt() * 100 / mQuotaInfo.max().toInt();
03062
03063 closeToQuota = ( ratio > 0 && ratio >= GlobalSettings::closeToQuotaThreshold() );
03064 }
03065
03066 return closeToQuota;
03067 }
03068
03069 KMCommand* KMFolderCachedImap::rescueUnsyncedMessages()
03070 {
03071 QValueList<unsigned long> newMsgs = findNewMessages();
03072 kdDebug() << k_funcinfo << newMsgs << " of " << count() << endl;
03073 if ( newMsgs.isEmpty() )
03074 return 0;
03075 KMFolder *dest = 0;
03076 bool manualMove = true;
03077 while ( GlobalSettings::autoLostFoundMove() ) {
03078
03079 KMFolder *inboxFolder = kmkernel->findFolderById( QString(".%1.directory/INBOX").arg( account()->id() ) );
03080 if ( !inboxFolder ) {
03081 kdWarning(5006) << k_funcinfo << "inbox not found!" << endl;
03082 break;
03083 }
03084 KMFolderDir *inboxDir = inboxFolder->child();
03085 if ( !inboxDir && !inboxFolder->storage() )
03086 break;
03087 assert( inboxFolder->storage()->folderType() == KMFolderTypeCachedImap );
03088
03089
03090 KMFolderNode *node;
03091 KMFolder *lfFolder = 0;
03092 if ( !(node = inboxDir->hasNamedFolder( i18n("lost+found") )) ) {
03093 kdDebug(5006) << k_funcinfo << "creating lost+found folder" << endl;
03094 KMFolder* folder = kmkernel->dimapFolderMgr()->createFolder(
03095 i18n("lost+found"), false, KMFolderTypeCachedImap, inboxDir );
03096 if ( !folder || !folder->storage() )
03097 break;
03098 static_cast<KMFolderCachedImap*>( folder->storage() )->initializeFrom(
03099 static_cast<KMFolderCachedImap*>( inboxFolder->storage() ) );
03100 folder->storage()->setContentsType( KMail::ContentsTypeMail );
03101 folder->storage()->writeConfig();
03102 lfFolder = folder;
03103 } else {
03104 kdDebug(5006) << k_funcinfo << "found lost+found folder" << endl;
03105 lfFolder = dynamic_cast<KMFolder*>( node );
03106 }
03107 if ( !lfFolder || !lfFolder->createChildFolder() || !lfFolder->storage() )
03108 break;
03109
03110
03111 QDate today = QDate::currentDate();
03112 QString baseName = folder()->label() + "-" + QString::number( today.year() )
03113 + (today.month() < 10 ? "0" : "" ) + QString::number( today.month() )
03114 + (today.day() < 10 ? "0" : "" ) + QString::number( today.day() );
03115 QString name = baseName;
03116 int suffix = 0;
03117 while ( (node = lfFolder->child()->hasNamedFolder( name )) ) {
03118 ++suffix;
03119 name = baseName + '-' + QString::number( suffix );
03120 }
03121 kdDebug(5006) << k_funcinfo << "creating lost+found folder " << name << endl;
03122 dest = kmkernel->dimapFolderMgr()->createFolder( name, false, KMFolderTypeCachedImap, lfFolder->child() );
03123 if ( !dest || !dest->storage() )
03124 break;
03125 static_cast<KMFolderCachedImap*>( dest->storage() )->initializeFrom(
03126 static_cast<KMFolderCachedImap*>( lfFolder->storage() ) );
03127 dest->storage()->setContentsType( contentsType() );
03128 dest->storage()->writeConfig();
03129
03130 KMessageBox::sorry( 0, i18n("<p>There are new messages in folder <b>%1</b>, which "
03131 "have not been uploaded to the server yet, but the folder has been deleted "
03132 "on the server or you do not "
03133 "have sufficient access rights on the folder to upload them.</p>"
03134 "<p>All affected messages will therefore be moved to <b>%2</b> "
03135 "to avoid data loss.</p>").arg( folder()->prettyURL() ).arg( dest->prettyURL() ),
03136 i18n("Insufficient access rights") );
03137 manualMove = false;
03138 break;
03139 }
03140
03141 if ( manualMove ) {
03142 const QString msg ( i18n( "<p>There are new messages in this folder (%1), which "
03143 "have not been uploaded to the server yet, but the folder has been deleted "
03144 "on the server or you do not "
03145 "have sufficient access rights on the folder now to upload them. "
03146 "Please contact your administrator to allow upload of new messages "
03147 "to you, or move them out of this folder.</p> "
03148 "<p>Do you want to move these messages to another folder now?</p>").arg( folder()->prettyURL() ) );
03149 if ( KMessageBox::warningYesNo( 0, msg, QString::null, i18n("Move"), i18n("Do Not Move") ) == KMessageBox::Yes ) {
03150 KMail::KMFolderSelDlg dlg( kmkernel->getKMMainWidget(),
03151 i18n("Move Messages to Folder"), true );
03152 if ( dlg.exec() ) {
03153 dest = dlg.folder();
03154 }
03155 }
03156 }
03157 if ( dest ) {
03158 QPtrList<KMMsgBase> msgs;
03159 for( int i = 0; i < count(); ++i ) {
03160 KMMsgBase *msg = getMsgBase( i );
03161 if( !msg ) continue;
03162 if ( msg->UID() == 0 )
03163 msgs.append( msg );
03164 }
03165 KMCommand *command = new KMMoveCommand( dest, msgs );
03166 command->start();
03167 return command;
03168 }
03169 return 0;
03170 }
03171
03172 void KMFolderCachedImap::rescueUnsyncedMessagesAndDeleteFolder( KMFolder *folder, bool root )
03173 {
03174 kdDebug() << k_funcinfo << folder << " " << root << endl;
03175 if ( root )
03176 mToBeDeletedAfterRescue.append( folder );
03177 folder->open("cachedimap");
03178 KMFolderCachedImap* storage = dynamic_cast<KMFolderCachedImap*>( folder->storage() );
03179 if ( storage ) {
03180 KMCommand *command = storage->rescueUnsyncedMessages();
03181 if ( command ) {
03182 connect( command, SIGNAL(completed(KMCommand*)),
03183 SLOT(slotRescueDone(KMCommand*)) );
03184 ++mRescueCommandCount;
03185 } else {
03186
03187
03188 folder->close("cachedimap");
03189 }
03190 }
03191 if ( folder->child() ) {
03192 KMFolderNode *node = folder->child()->first();
03193 while (node) {
03194 if (!node->isDir() ) {
03195 KMFolder *subFolder = static_cast<KMFolder*>( node );
03196 rescueUnsyncedMessagesAndDeleteFolder( subFolder, false );
03197 }
03198 node = folder->child()->next();
03199 }
03200 }
03201 }
03202
03203 void KMFolderCachedImap::slotRescueDone(KMCommand * command)
03204 {
03205
03206 if ( command )
03207 --mRescueCommandCount;
03208 if ( mRescueCommandCount > 0 )
03209 return;
03210 for ( QValueList<KMFolder*>::ConstIterator it = mToBeDeletedAfterRescue.constBegin();
03211 it != mToBeDeletedAfterRescue.constEnd(); ++it ) {
03212 kmkernel->dimapFolderMgr()->remove( *it );
03213 }
03214 mToBeDeletedAfterRescue.clear();
03215 serverSyncInternal();
03216 }
03217
03218 void KMFolderCachedImap::slotRenameFolderFinished()
03219 {
03220
03221
03222
03223 open( "cachedimap" );
03224 serverSyncInternal();
03225 }
03226
03227 bool KMFolderCachedImap::canDeleteMessages() const
03228 {
03229 if ( isReadOnly() )
03230 return false;
03231 if ( mUserRightsState == KMail::ACLJobs::Ok && !(userRights() & ACLJobs::Delete) )
03232 return false;
03233 return true;
03234 }
03235
03236 bool KMFolderCachedImap::mailCheckInProgress() const
03237 {
03238 return mSyncState != SYNC_STATE_INITIAL;
03239 }
03240
03241 #include "kmfoldercachedimap.moc"