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 for ( KMFolder* doomed=toRemove.first(); doomed; doomed = toRemove.next() ) {
02229 rescueUnsyncedMessagesAndDeleteFolder( doomed );
02230 }
02231
02232 mProgress += 5;
02233
02234
02235 slotRescueDone( 0 );
02236 }
02237
02238
02239 void KMFolderCachedImap::listDirectory2()
02240 {
02241 QString path = folder()->path();
02242 kmkernel->dimapFolderMgr()->quiet(true);
02243
02244 bool root = ( this == mAccount->rootFolder() );
02245 if ( root && !mAccount->hasInbox() )
02246 {
02247 KMFolderCachedImap *f = 0;
02248 KMFolderNode *node;
02249
02250 for (node = folder()->child()->first(); node; node = folder()->child()->next())
02251 if (!node->isDir() && node->name() == "INBOX") break;
02252 if (node) {
02253 f = static_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage());
02254 } else {
02255 KMFolder* newFolder = folder()->child()->createFolder("INBOX", true, KMFolderTypeCachedImap);
02256 if ( newFolder ) {
02257 f = static_cast<KMFolderCachedImap*>(newFolder->storage());
02258 }
02259 }
02260 if ( f ) {
02261 f->setAccount( mAccount );
02262 f->setImapPath( "/INBOX/" );
02263 f->folder()->setLabel( i18n("inbox") );
02264 }
02265 if (!node) {
02266 if ( f )
02267 f->close("cachedimap");
02268 kmkernel->dimapFolderMgr()->contentsChanged();
02269 }
02270
02271 mAccount->setHasInbox( true );
02272 }
02273
02274 if ( root && !mSubfolderNames.isEmpty() ) {
02275 KMFolderCachedImap* parent =
02276 findParent( mSubfolderPaths.first(), mSubfolderNames.first() );
02277 if ( parent ) {
02278 kdDebug(5006) << "KMFolderCachedImap::listDirectory2 - pass listing to "
02279 << parent->label() << endl;
02280 mSubfolderNames.clear();
02281 }
02282 }
02283
02284
02285 QValueVector<int> foldersNewOnServer;
02286 for (uint i = 0; i < mSubfolderNames.count(); i++) {
02287
02288
02289 KMFolderCachedImap *f = 0;
02290 KMFolderNode *node = 0;
02291 for (node = folder()->child()->first(); node;
02292 node = folder()->child()->next())
02293 if (!node->isDir() && node->name() == mSubfolderNames[i]) break;
02294
02295 if (!node) {
02296
02297
02298 QString subfolderPath = mSubfolderPaths[i];
02299
02300
02301
02302 bool locallyDeleted = mAccount->isDeletedFolder( subfolderPath );
02303
02304
02305
02306 if ( !locallyDeleted && mAccount->isPreviouslyDeletedFolder( subfolderPath ) ) {
02307 locallyDeleted = KMessageBox::warningYesNo(
02308 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;
02309 }
02310
02311 if ( locallyDeleted ) {
02312 kdDebug(5006) << subfolderPath << " was deleted locally => delete on server." << endl;
02313 foldersForDeletionOnServer += mAccount->deletedFolderPaths( subfolderPath );
02314 } else {
02315 kdDebug(5006) << subfolderPath << " is a new folder on the server => create local cache" << endl;
02316 foldersNewOnServer.append( i );
02317 }
02318 } else {
02319 if( static_cast<KMFolder*>(node)->folderType() == KMFolderTypeCachedImap )
02320 f = dynamic_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage());
02321 if( f ) {
02322
02323
02324
02325 f->setAccount(mAccount);
02326 f->setNoContent(mSubfolderMimeTypes[i] == "inode/directory");
02327 f->setNoChildren(mSubfolderMimeTypes[i] == "message/digest");
02328 f->setImapPath(mSubfolderPaths[i]);
02329 }
02330 }
02331 }
02332
02333
02334
02335
02336
02337
02338
02339
02340
02341
02342
02343 if ( GlobalSettings::self()->showOnlyGroupwareFoldersForGroupwareAccount()
02344 && GlobalSettings::self()->theIMAPResourceAccount() == (int)mAccount->id()
02345 && mAccount->hasAnnotationSupport()
02346 && GlobalSettings::self()->theIMAPResourceEnabled()
02347 && !foldersNewOnServer.isEmpty() ) {
02348
02349 QStringList paths;
02350 for ( uint i = 0; i < foldersNewOnServer.count(); ++i )
02351 paths << mSubfolderPaths[ foldersNewOnServer[i] ];
02352
02353 AnnotationJobs::MultiUrlGetAnnotationJob* job =
02354 AnnotationJobs::multiUrlGetAnnotation( mAccount->slave(), mAccount->getUrl(), paths, KOLAB_FOLDERTYPE );
02355 ImapAccountBase::jobData jd( QString::null, folder() );
02356 jd.cancellable = true;
02357 mAccount->insertJob(job, jd);
02358 connect( job, SIGNAL(result(KIO::Job *)),
02359 SLOT(slotMultiUrlGetAnnotationResult(KIO::Job *)) );
02360
02361 } else {
02362 createFoldersNewOnServerAndFinishListing( foldersNewOnServer );
02363 }
02364 }
02365
02366 void KMFolderCachedImap::createFoldersNewOnServerAndFinishListing( const QValueVector<int> foldersNewOnServer )
02367 {
02368 for ( uint i = 0; i < foldersNewOnServer.count(); ++i ) {
02369 int idx = foldersNewOnServer[i];
02370 KMFolder* newFolder = folder()->child()->createFolder( mSubfolderNames[idx], false, KMFolderTypeCachedImap);
02371 if (newFolder) {
02372 KMFolderCachedImap *f = dynamic_cast<KMFolderCachedImap*>(newFolder->storage());
02373 kdDebug(5006) << " ####### Locally creating folder " << mSubfolderNames[idx] <<endl;
02374 f->close("cachedimap");
02375 f->setAccount(mAccount);
02376 f->mAnnotationFolderType = "FROMSERVER";
02377 f->setNoContent(mSubfolderMimeTypes[idx] == "inode/directory");
02378 f->setNoChildren(mSubfolderMimeTypes[idx] == "message/digest");
02379 f->setImapPath(mSubfolderPaths[idx]);
02380 f->mFolderAttributes = mSubfolderAttributes[idx];
02381 mNewlyCreatedSubfolders.append( QGuardedPtr<KMFolderCachedImap>( f ) );
02382 kdDebug(5006) << " ####### Attributes: " << f->mFolderAttributes <<endl;
02383
02384 kmkernel->dimapFolderMgr()->contentsChanged();
02385 } else {
02386 kdDebug(5006) << "can't create folder " << mSubfolderNames[idx] <<endl;
02387 }
02388 }
02389
02390 kmkernel->dimapFolderMgr()->quiet(false);
02391 emit listComplete(this);
02392 if ( !mPersonalNamespacesCheckDone ) {
02393
02394 mSyncState = SYNC_STATE_LIST_NAMESPACES;
02395 }
02396 serverSyncInternal();
02397 }
02398
02399
02400 KMFolderCachedImap* KMFolderCachedImap::findParent( const QString& path,
02401 const QString& name )
02402 {
02403 QString parent = path.left( path.length() - name.length() - 2 );
02404 if ( parent.length() > 1 )
02405 {
02406
02407 parent = parent.right( parent.length() - 1 );
02408 if ( parent != label() )
02409 {
02410 KMFolderNode *node = folder()->child()->first();
02411
02412 while ( node )
02413 {
02414 if ( node->name() == parent )
02415 {
02416 KMFolder* fld = static_cast<KMFolder*>(node);
02417 KMFolderCachedImap* imapFld =
02418 static_cast<KMFolderCachedImap*>( fld->storage() );
02419 return imapFld;
02420 }
02421 node = folder()->child()->next();
02422 }
02423 }
02424 }
02425 return 0;
02426 }
02427
02428 void KMFolderCachedImap::slotSubFolderComplete(KMFolderCachedImap* sub, bool success)
02429 {
02430 Q_UNUSED(sub);
02431
02432 if ( success ) {
02433 serverSyncInternal();
02434 }
02435 else
02436 {
02437
02438 if ( mCurrentSubfolder ) {
02439 Q_ASSERT( sub == mCurrentSubfolder );
02440 disconnectSubFolderSignals();
02441 }
02442
02443
02444
02445 mSubfoldersForSync.clear();
02446 mSyncState = SYNC_STATE_INITIAL;
02447 close("cachedimap");
02448 emit syncStateChanged();
02449 emit folderComplete( this, false );
02450 }
02451 }
02452
02453 void KMFolderCachedImap::slotSubFolderCloseToQuotaChanged()
02454 {
02455 if ( !mQuotaOnly ) {
02456 mSomeSubFolderCloseToQuotaChanged = true;
02457 }
02458 }
02459
02460 void KMFolderCachedImap::slotSimpleData(KIO::Job * job, const QByteArray & data)
02461 {
02462 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
02463 if (it == mAccount->jobsEnd()) return;
02464 QBuffer buff((*it).data);
02465 buff.open(IO_WriteOnly | IO_Append);
02466 buff.writeBlock(data.data(), data.size());
02467 buff.close();
02468 }
02469
02470 FolderJob*
02471 KMFolderCachedImap::doCreateJob( KMMessage *msg, FolderJob::JobType jt, KMFolder *folder,
02472 QString, const AttachmentStrategy* ) const
02473 {
02474 QPtrList<KMMessage> msgList;
02475 msgList.append( msg );
02476 CachedImapJob *job = new CachedImapJob( msgList, jt, folder? static_cast<KMFolderCachedImap*>( folder->storage() ):0 );
02477 job->setParentFolder( this );
02478 return job;
02479 }
02480
02481 FolderJob*
02482 KMFolderCachedImap::doCreateJob( QPtrList<KMMessage>& msgList, const QString& sets,
02483 FolderJob::JobType jt, KMFolder *folder ) const
02484 {
02485
02486 Q_UNUSED( sets );
02487 CachedImapJob *job = new CachedImapJob( msgList, jt, folder? static_cast<KMFolderCachedImap*>( folder->storage() ):0 );
02488 job->setParentFolder( this );
02489 return job;
02490 }
02491
02492 void
02493 KMFolderCachedImap::setUserRights( unsigned int userRights, KMail::ACLJobs::ACLFetchState state )
02494 {
02495 mUserRights = userRights;
02496 mUserRightsState = state;
02497 writeConfigKeysWhichShouldNotGetOverwrittenByReadConfig();
02498 }
02499
02500 void
02501 KMFolderCachedImap::slotReceivedUserRights( KMFolder* folder )
02502 {
02503 if ( folder->storage() == this ) {
02504 disconnect( mAccount, SIGNAL( receivedUserRights( KMFolder* ) ),
02505 this, SLOT( slotReceivedUserRights( KMFolder* ) ) );
02506 if ( mUserRightsState == KMail::ACLJobs::Ok ) {
02507 setReadOnly( ( mUserRights & KMail::ACLJobs::Insert ) == 0 );
02508 }
02509 mProgress += 5;
02510 serverSyncInternal();
02511 }
02512 }
02513
02514 void
02515 KMFolderCachedImap::setReadOnly( bool readOnly )
02516 {
02517 if ( readOnly != mReadOnly ) {
02518 mReadOnly = readOnly;
02519 emit readOnlyChanged( folder() );
02520 }
02521 }
02522
02523 void
02524 KMFolderCachedImap::slotReceivedACL( KMFolder* folder, KIO::Job* job, const KMail::ACLList& aclList )
02525 {
02526 if ( folder->storage() == this ) {
02527 disconnect( mAccount, SIGNAL(receivedACL( KMFolder*, KIO::Job*, const KMail::ACLList& )),
02528 this, SLOT(slotReceivedACL( KMFolder*, KIO::Job*, const KMail::ACLList& )) );
02529 mACLListState = job->error() ? KMail::ACLJobs::FetchFailed : KMail::ACLJobs::Ok;
02530 mACLList = aclList;
02531 serverSyncInternal();
02532 }
02533 }
02534
02535 void
02536 KMFolderCachedImap::slotStorageQuotaResult( const QuotaInfo& info )
02537 {
02538 setQuotaInfo( info );
02539 }
02540
02541 void KMFolderCachedImap::setQuotaInfo( const QuotaInfo & info )
02542 {
02543 if ( info != mQuotaInfo ) {
02544 const bool wasCloseToQuota = isCloseToQuota();
02545 mQuotaInfo = info;
02546 writeConfigKeysWhichShouldNotGetOverwrittenByReadConfig();
02547 if ( wasCloseToQuota != isCloseToQuota() ) {
02548 emit closeToQuotaChanged();
02549 }
02550 emit folderSizeChanged();
02551 }
02552 }
02553
02554 void
02555 KMFolderCachedImap::setACLList( const ACLList& arr )
02556 {
02557 mACLList = arr;
02558 mACLListState = KMail::ACLJobs::Ok;
02559 }
02560
02561 void
02562 KMFolderCachedImap::slotMultiSetACLResult(KIO::Job *job)
02563 {
02564 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
02565 if ( it == mAccount->jobsEnd() ) return;
02566 if ( (*it).parent != folder() ) return;
02567
02568 if ( job->error() )
02569
02570
02571 job->showErrorDialog();
02572 else
02573 kmkernel->iCalIface().addFolderChange( folder(), KMailICalIfaceImpl::ACL );
02574
02575 if (mAccount->slave()) mAccount->removeJob(job);
02576 serverSyncInternal();
02577 }
02578
02579 void
02580 KMFolderCachedImap::slotACLChanged( const QString& userId, int permissions )
02581 {
02582
02583
02584 for( ACLList::Iterator it = mACLList.begin(); it != mACLList.end(); ++it ) {
02585 if ( (*it).userId == userId && (*it).permissions == permissions ) {
02586 if ( permissions == -1 )
02587 mACLList.erase( it );
02588 else
02589 (*it).changed = false;
02590 return;
02591 }
02592 }
02593 }
02594
02595
02596 void KMFolderCachedImap::resetSyncState()
02597 {
02598 if ( mSyncState == SYNC_STATE_INITIAL ) return;
02599 mSubfoldersForSync.clear();
02600 mNewlyCreatedSubfolders.clear();
02601 mSyncState = SYNC_STATE_INITIAL;
02602 close("cachedimap");
02603
02604 KPIM::ProgressItem *progressItem = mAccount->mailCheckProgressItem();
02605 QString str = i18n("Aborted");
02606 if (progressItem)
02607 progressItem->setStatus( str );
02608 emit statusMsg( str );
02609 emit syncStateChanged();
02610 }
02611
02612 void KMFolderCachedImap::slotIncreaseProgress()
02613 {
02614 mProgress += 5;
02615 }
02616
02617 void KMFolderCachedImap::newState( int progress, const QString& syncStatus )
02618 {
02619
02620 KPIM::ProgressItem *progressItem = mAccount->mailCheckProgressItem();
02621 if( progressItem )
02622 progressItem->setCompletedItems( progress );
02623 if ( !syncStatus.isEmpty() ) {
02624 QString str;
02625
02626 if ( mAccount->imapFolder() == this )
02627 str = syncStatus;
02628 else
02629 str = QString( "%1: %2" ).arg( label() ).arg( syncStatus );
02630 if( progressItem )
02631 progressItem->setStatus( str );
02632 emit statusMsg( str );
02633 }
02634 if( progressItem )
02635 progressItem->updateProgress();
02636 }
02637
02638 void KMFolderCachedImap::setSubfolderState( imapState state )
02639 {
02640 mSubfolderState = state;
02641 if ( state == imapNoInformation && folder()->child() )
02642 {
02643
02644 KMFolderNode* node;
02645 QPtrListIterator<KMFolderNode> it( *folder()->child() );
02646 for ( ; (node = it.current()); )
02647 {
02648 ++it;
02649 if (node->isDir()) continue;
02650 KMFolder *folder = static_cast<KMFolder*>(node);
02651 static_cast<KMFolderCachedImap*>(folder->storage())->setSubfolderState( state );
02652 }
02653 }
02654 }
02655
02656 void KMFolderCachedImap::setImapPath(const QString &path)
02657 {
02658 mImapPath = path;
02659 }
02660
02661 static bool isFolderTypeKnownToUs( const QString &type )
02662 {
02663 for ( uint i = 0 ; i <= ContentsTypeLast; ++i ) {
02664 FolderContentsType contentsType = static_cast<KMail::FolderContentsType>( i );
02665 if ( type == KMailICalIfaceImpl::annotationForContentsType( contentsType ) )
02666 return true;
02667 }
02668 return false;
02669 }
02670
02671
02672
02673
02674
02675
02676 void KMFolderCachedImap::updateAnnotationFolderType()
02677 {
02678 QString oldType = mAnnotationFolderType;
02679 QString oldSubType;
02680 int dot = oldType.find( '.' );
02681 if ( dot != -1 ) {
02682 oldType.truncate( dot );
02683 oldSubType = mAnnotationFolderType.mid( dot + 1 );
02684 }
02685
02686 QString newType, newSubType;
02687
02688 if ( kmkernel->iCalIface().storageFormat( folder() ) == KMailICalIfaceImpl::StorageXML ) {
02689 newType = KMailICalIfaceImpl::annotationForContentsType( mContentsType );
02690 if ( kmkernel->iCalIface().isStandardResourceFolder( folder() ) )
02691 newSubType = "default";
02692 else if ( oldSubType != "default" )
02693 newSubType = oldSubType;
02694 }
02695
02696
02697
02698
02699 const bool changingTypeAllowed = isFolderTypeKnownToUs( oldType ) ||
02700 ( mContentsType != ContentsTypeMail );
02701
02702
02703 if ( ( newType != oldType || newSubType != oldSubType ) && changingTypeAllowed ) {
02704 mAnnotationFolderType = newType + ( newSubType.isEmpty() ? QString::null : "."+newSubType );
02705 mAnnotationFolderTypeChanged = true;
02706 kdDebug(5006) << mImapPath << ": updateAnnotationFolderType: '" << mAnnotationFolderType << "', was (" << oldType << " " << oldSubType << ") => mAnnotationFolderTypeChanged set to TRUE" << endl;
02707 }
02708
02709 writeConfigKeysWhichShouldNotGetOverwrittenByReadConfig();
02710 }
02711
02712 void KMFolderCachedImap::setIncidencesFor( IncidencesFor incfor )
02713 {
02714 if ( mIncidencesFor != incfor ) {
02715 mIncidencesFor = incfor;
02716 mIncidencesForChanged = true;
02717 }
02718 }
02719
02720 void KMFolderCachedImap::setSharedSeenFlags(bool b)
02721 {
02722 if ( mSharedSeenFlags != b ) {
02723 mSharedSeenFlags = b;
02724 mSharedSeenFlagsChanged = true;
02725 }
02726 }
02727
02728 void KMFolderCachedImap::slotAnnotationResult(const QString& entry, const QString& value, bool found)
02729 {
02730 if ( entry == KOLAB_FOLDERTYPE ) {
02731
02732
02733
02734
02735
02736 if ( found ) {
02737 QString type = value;
02738 QString subtype;
02739 int dot = value.find( '.' );
02740 if ( dot != -1 ) {
02741 type.truncate( dot );
02742 subtype = value.mid( dot + 1 );
02743 }
02744 bool foundKnownType = false;
02745 for ( uint i = 0 ; i <= ContentsTypeLast; ++i ) {
02746 FolderContentsType contentsType = static_cast<KMail::FolderContentsType>( i );
02747 if ( type == KMailICalIfaceImpl::annotationForContentsType( contentsType ) ) {
02748
02749
02750 if ( contentsType != ContentsTypeMail )
02751 kmkernel->iCalIface().setStorageFormat( folder(), KMailICalIfaceImpl::StorageXML );
02752 mAnnotationFolderType = value;
02753 if ( folder()->parent()->owner()->idString() != GlobalSettings::self()->theIMAPResourceFolderParent()
02754 && GlobalSettings::self()->theIMAPResourceEnabled()
02755 && subtype == "default" ) {
02756
02757
02758 mAnnotationFolderType = type;
02759 kdDebug(5006) << mImapPath << ": slotGetAnnotationResult: parent folder is " << folder()->parent()->owner()->idString() << " => truncating annotation to " << value << endl;
02760 }
02761 setContentsType( contentsType );
02762 mAnnotationFolderTypeChanged = false;
02763 foundKnownType = true;
02764
02765
02766
02767
02768
02769 if ( contentsType != ContentsTypeMail )
02770 markUnreadAsRead();
02771
02772 break;
02773 }
02774 }
02775 if ( !foundKnownType ) {
02776
02777
02778
02779
02780 mAnnotationFolderTypeChanged = false;
02781 mAnnotationFolderType = value;
02782 setContentsType( ContentsTypeMail );
02783 }
02784
02785
02786 writeConfigKeysWhichShouldNotGetOverwrittenByReadConfig();
02787
02788 }
02789 else if ( !mReadOnly ) {
02790
02791
02792 mAnnotationFolderTypeChanged = true;
02793 }
02794 } else if ( entry == KOLAB_INCIDENCESFOR ) {
02795 if ( found ) {
02796 mIncidencesFor = incidencesForFromString( value );
02797 Q_ASSERT( mIncidencesForChanged == false );
02798 }
02799 } else if ( entry == KOLAB_SHAREDSEEN ) {
02800 if ( found ) {
02801 mSharedSeenFlags = value == "true";
02802 }
02803 }
02804 }
02805
02806 void KMFolderCachedImap::slotGetAnnotationResult( KIO::Job* job )
02807 {
02808 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
02809 Q_ASSERT( it != mAccount->jobsEnd() );
02810 if ( it == mAccount->jobsEnd() ) return;
02811 Q_ASSERT( (*it).parent == folder() );
02812 if ( (*it).parent != folder() ) return;
02813
02814 AnnotationJobs::GetAnnotationJob* annjob = static_cast<AnnotationJobs::GetAnnotationJob *>( job );
02815 if ( annjob->error() ) {
02816 if ( job->error() == KIO::ERR_UNSUPPORTED_ACTION ) {
02817
02818 if ( GlobalSettings::self()->theIMAPResourceStorageFormat() == GlobalSettings::EnumTheIMAPResourceStorageFormat::XML
02819 && (uint)GlobalSettings::self()->theIMAPResourceAccount() == mAccount->id() )
02820 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() ) );
02821 mAccount->setHasNoAnnotationSupport();
02822 }
02823 else
02824 kdWarning(5006) << "slotGetAnnotationResult: " << job->errorString() << endl;
02825 }
02826
02827 if (mAccount->slave()) mAccount->removeJob(job);
02828 mProgress += 2;
02829 serverSyncInternal();
02830 }
02831
02832 void KMFolderCachedImap::slotMultiUrlGetAnnotationResult( KIO::Job* job )
02833 {
02834 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
02835 Q_ASSERT( it != mAccount->jobsEnd() );
02836 if ( it == mAccount->jobsEnd() ) return;
02837 Q_ASSERT( (*it).parent == folder() );
02838 if ( (*it).parent != folder() ) return;
02839
02840 QValueVector<int> folders;
02841 AnnotationJobs::MultiUrlGetAnnotationJob* annjob
02842 = static_cast<AnnotationJobs::MultiUrlGetAnnotationJob *>( job );
02843 if ( annjob->error() ) {
02844 if ( job->error() == KIO::ERR_UNSUPPORTED_ACTION ) {
02845
02846 if ( GlobalSettings::self()->theIMAPResourceStorageFormat() == GlobalSettings::EnumTheIMAPResourceStorageFormat::XML
02847 && (uint)GlobalSettings::self()->theIMAPResourceAccount() == mAccount->id() )
02848 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() ) );
02849 mAccount->setHasNoAnnotationSupport();
02850 }
02851 else
02852 kdWarning(5006) << "slotGetMultiUrlAnnotationResult: " << job->errorString() << endl;
02853 } else {
02854
02855 QMap<QString, QString> annotations = annjob->annotations();
02856 QMap<QString, QString>::Iterator it = annotations.begin();
02857 for ( ; it != annotations.end(); ++it ) {
02858 const QString folderPath = it.key();
02859 const QString annotation = it.data();
02860 kdDebug(5006) << k_funcinfo << "Folder: " << folderPath << " has type: " << annotation << endl;
02861
02862 QString type(annotation);
02863 int dot = annotation.find( '.' );
02864 if ( dot != -1 ) type.truncate( dot );
02865 type = type.simplifyWhiteSpace();
02866
02867 const int idx = mSubfolderPaths.findIndex( folderPath );
02868 const bool isNoContent = mSubfolderMimeTypes[idx] == "inode/directory";
02869 if ( ( isNoContent && type.isEmpty() )
02870 || ( !type.isEmpty() && type != KMailICalIfaceImpl::annotationForContentsType( ContentsTypeMail ) ) ) {
02871 folders.append( idx );
02872 kdDebug(5006) << k_funcinfo << " subscribing to: " << folderPath << endl;
02873 } else {
02874 kdDebug(5006) << k_funcinfo << " automatically unsubscribing from: " << folderPath << endl;
02875 mAccount->changeLocalSubscription( folderPath, false );
02876 }
02877 }
02878 }
02879
02880 if (mAccount->slave()) mAccount->removeJob(job);
02881 createFoldersNewOnServerAndFinishListing( folders );
02882 }
02883
02884 void KMFolderCachedImap::slotQuotaResult( KIO::Job* job )
02885 {
02886 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
02887 Q_ASSERT( it != mAccount->jobsEnd() );
02888 if ( it == mAccount->jobsEnd() ) return;
02889 Q_ASSERT( (*it).parent == folder() );
02890 if ( (*it).parent != folder() ) return;
02891
02892 QuotaJobs::GetStorageQuotaJob* quotajob = static_cast<QuotaJobs::GetStorageQuotaJob *>( job );
02893 QuotaInfo empty;
02894 if ( quotajob->error() ) {
02895 if ( job->error() == KIO::ERR_UNSUPPORTED_ACTION ) {
02896
02897 mAccount->setHasNoQuotaSupport();
02898 setQuotaInfo( empty );
02899 }
02900 else
02901 kdWarning(5006) << "slotGetQuotaResult: " << job->errorString() << endl;
02902 }
02903
02904 if (mAccount->slave()) mAccount->removeJob(job);
02905 mProgress += 2;
02906 serverSyncInternal();
02907 }
02908
02909 void
02910 KMFolderCachedImap::slotAnnotationChanged( const QString& entry, const QString& attribute, const QString& value )
02911 {
02912 Q_UNUSED( attribute );
02913 Q_UNUSED( value );
02914
02915 if ( entry == KOLAB_FOLDERTYPE )
02916 mAnnotationFolderTypeChanged = false;
02917 else if ( entry == KOLAB_INCIDENCESFOR ) {
02918 mIncidencesForChanged = false;
02919
02920
02921 kmkernel->iCalIface().addFolderChange( folder(), KMailICalIfaceImpl::ACL );
02922 } else if ( entry == KOLAB_SHAREDSEEN ) {
02923 mSharedSeenFlagsChanged = false;
02924 }
02925 }
02926
02927 void KMFolderCachedImap::slotTestAnnotationResult(KIO::Job *job)
02928 {
02929 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
02930 Q_ASSERT( it != mAccount->jobsEnd() );
02931 if ( it == mAccount->jobsEnd() ) return;
02932 Q_ASSERT( (*it).parent == folder() );
02933 if ( (*it).parent != folder() ) return;
02934
02935 mAccount->setAnnotationCheckPassed( true );
02936 if ( job->error() ) {
02937 kdDebug(5006) << "Test Annotation was not passed, disabling annotation support" << endl;
02938 mAccount->setHasNoAnnotationSupport( );
02939 } else {
02940 kdDebug(5006) << "Test Annotation was passed OK" << endl;
02941 }
02942 if (mAccount->slave()) mAccount->removeJob(job);
02943 serverSyncInternal();
02944 }
02945
02946 void
02947 KMFolderCachedImap::slotSetAnnotationResult(KIO::Job *job)
02948 {
02949 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
02950 if ( it == mAccount->jobsEnd() ) return;
02951 if ( (*it).parent != folder() ) return;
02952
02953 bool cont = true;
02954 if ( job->error() ) {
02955
02956 if ( job->error() == KIO::ERR_UNSUPPORTED_ACTION && contentsType() == ContentsTypeMail ) {
02957 if (mAccount->slave()) mAccount->removeJob(job);
02958 } else {
02959 cont = mAccount->handleJobError( job, i18n( "Error while setting annotation: " ) + '\n' );
02960 }
02961 } else {
02962 if (mAccount->slave()) mAccount->removeJob(job);
02963 }
02964 if ( cont )
02965 serverSyncInternal();
02966 }
02967
02968 void KMFolderCachedImap::slotUpdateLastUid()
02969 {
02970 if( mTentativeHighestUid != 0 ) {
02971
02972
02973
02974
02975
02976
02977
02978
02979
02980
02981
02982 bool sane = count() == 0;
02983
02984 for (int i=0;i<count(); i++ ) {
02985 ulong uid = getMsgBase(i)->UID();
02986 if ( uid > mTentativeHighestUid && uid > lastUid() ) {
02987 kdWarning(5006) << "DANGER: Either the server listed a wrong highest uid, "
02988 "or we parsed it wrong. Send email to adam@kde.org, please, and include this log." << endl;
02989 kdWarning(5006) << "uid: " << uid << " mTentativeHighestUid: " << mTentativeHighestUid << endl;
02990 assert( false );
02991 break;
02992 } else {
02993 sane = true;
02994 }
02995 }
02996 if (sane) {
02997 if ( GlobalSettings::self()->mailLossDebug() ) {
02998 kdDebug(5006) << "Tentative highest UID test was sane, writing out: " << mTentativeHighestUid << endl;
02999 }
03000 setLastUid( mTentativeHighestUid );
03001 }
03002 }
03003 mTentativeHighestUid = 0;
03004 }
03005
03006 bool KMFolderCachedImap::isMoveable() const
03007 {
03008 return ( hasChildren() == HasNoChildren &&
03009 !folder()->isSystemFolder() ) ? true : false;
03010 }
03011
03012 void KMFolderCachedImap::slotFolderDeletionOnServerFinished()
03013 {
03014 for ( QStringList::const_iterator it = foldersForDeletionOnServer.constBegin();
03015 it != foldersForDeletionOnServer.constEnd(); ++it ) {
03016 KURL url( mAccount->getUrl() );
03017 url.setPath( *it );
03018 kmkernel->iCalIface().folderDeletedOnServer( url );
03019 }
03020 serverSyncInternal();
03021 }
03022
03023 int KMFolderCachedImap::createIndexFromContentsRecursive()
03024 {
03025 if ( !folder() || !folder()->child() )
03026 return 0;
03027
03028 KMFolderNode *node = 0;
03029 for( QPtrListIterator<KMFolderNode> it( *folder()->child() ); (node = it.current()); ++it ) {
03030 if( !node->isDir() ) {
03031 KMFolderCachedImap* storage = static_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage());
03032 kdDebug() << k_funcinfo << "Re-indexing: " << storage->folder()->label() << endl;
03033 int rv = storage->createIndexFromContentsRecursive();
03034 if ( rv > 0 )
03035 return rv;
03036 }
03037 }
03038
03039 return createIndexFromContents();
03040 }
03041
03042 void KMFolderCachedImap::setAlarmsBlocked( bool blocked )
03043 {
03044 mAlarmsBlocked = blocked;
03045 }
03046
03047 bool KMFolderCachedImap::alarmsBlocked() const
03048 {
03049 return mAlarmsBlocked;
03050 }
03051
03052 bool KMFolderCachedImap::isCloseToQuota() const
03053 {
03054 bool closeToQuota = false;
03055 if ( mQuotaInfo.isValid() && mQuotaInfo.max().toInt() > 0 ) {
03056 const int ratio = mQuotaInfo.current().toInt() * 100 / mQuotaInfo.max().toInt();
03057
03058 closeToQuota = ( ratio > 0 && ratio >= GlobalSettings::closeToQuotaThreshold() );
03059 }
03060
03061 return closeToQuota;
03062 }
03063
03064 KMCommand* KMFolderCachedImap::rescueUnsyncedMessages()
03065 {
03066 QValueList<unsigned long> newMsgs = findNewMessages();
03067 kdDebug() << k_funcinfo << newMsgs << " of " << count() << endl;
03068 if ( newMsgs.isEmpty() )
03069 return 0;
03070 KMFolder *dest = 0;
03071 bool manualMove = true;
03072 while ( GlobalSettings::autoLostFoundMove() ) {
03073
03074 KMFolder *inboxFolder = kmkernel->findFolderById( QString(".%1.directory/INBOX").arg( account()->id() ) );
03075 if ( !inboxFolder ) {
03076 kdWarning(5006) << k_funcinfo << "inbox not found!" << endl;
03077 break;
03078 }
03079 KMFolderDir *inboxDir = inboxFolder->child();
03080 if ( !inboxDir && !inboxFolder->storage() )
03081 break;
03082 assert( inboxFolder->storage()->folderType() == KMFolderTypeCachedImap );
03083
03084
03085 KMFolderNode *node;
03086 KMFolder *lfFolder = 0;
03087 if ( !(node = inboxDir->hasNamedFolder( i18n("lost+found") )) ) {
03088 kdDebug(5006) << k_funcinfo << "creating lost+found folder" << endl;
03089 KMFolder* folder = kmkernel->dimapFolderMgr()->createFolder(
03090 i18n("lost+found"), false, KMFolderTypeCachedImap, inboxDir );
03091 if ( !folder || !folder->storage() )
03092 break;
03093 static_cast<KMFolderCachedImap*>( folder->storage() )->initializeFrom(
03094 static_cast<KMFolderCachedImap*>( inboxFolder->storage() ) );
03095 folder->storage()->setContentsType( KMail::ContentsTypeMail );
03096 folder->storage()->writeConfig();
03097 lfFolder = folder;
03098 } else {
03099 kdDebug(5006) << k_funcinfo << "found lost+found folder" << endl;
03100 lfFolder = dynamic_cast<KMFolder*>( node );
03101 }
03102 if ( !lfFolder || !lfFolder->createChildFolder() || !lfFolder->storage() )
03103 break;
03104
03105
03106 QDate today = QDate::currentDate();
03107 QString baseName = folder()->label() + "-" + QString::number( today.year() )
03108 + (today.month() < 10 ? "0" : "" ) + QString::number( today.month() )
03109 + (today.day() < 10 ? "0" : "" ) + QString::number( today.day() );
03110 QString name = baseName;
03111 int suffix = 0;
03112 while ( (node = lfFolder->child()->hasNamedFolder( name )) ) {
03113 ++suffix;
03114 name = baseName + '-' + QString::number( suffix );
03115 }
03116 kdDebug(5006) << k_funcinfo << "creating lost+found folder " << name << endl;
03117 dest = kmkernel->dimapFolderMgr()->createFolder( name, false, KMFolderTypeCachedImap, lfFolder->child() );
03118 if ( !dest || !dest->storage() )
03119 break;
03120 static_cast<KMFolderCachedImap*>( dest->storage() )->initializeFrom(
03121 static_cast<KMFolderCachedImap*>( lfFolder->storage() ) );
03122 dest->storage()->setContentsType( contentsType() );
03123 dest->storage()->writeConfig();
03124
03125 KMessageBox::sorry( 0, i18n("<p>There are new messages in folder <b>%1</b>, which "
03126 "have not been uploaded to the server yet, but the folder has been deleted "
03127 "on the server or you do not "
03128 "have sufficient access rights on the folder to upload them.</p>"
03129 "<p>All affected messages will therefore be moved to <b>%2</b> "
03130 "to avoid data loss.</p>").arg( folder()->prettyURL() ).arg( dest->prettyURL() ),
03131 i18n("Insufficient access rights") );
03132 manualMove = false;
03133 break;
03134 }
03135
03136 if ( manualMove ) {
03137 const QString msg ( i18n( "<p>There are new messages in this folder (%1), which "
03138 "have not been uploaded to the server yet, but the folder has been deleted "
03139 "on the server or you do not "
03140 "have sufficient access rights on the folder now to upload them. "
03141 "Please contact your administrator to allow upload of new messages "
03142 "to you, or move them out of this folder.</p> "
03143 "<p>Do you want to move these messages to another folder now?</p>").arg( folder()->prettyURL() ) );
03144 if ( KMessageBox::warningYesNo( 0, msg, QString::null, i18n("Move"), i18n("Do Not Move") ) == KMessageBox::Yes ) {
03145 KMail::KMFolderSelDlg dlg( kmkernel->getKMMainWidget(),
03146 i18n("Move Messages to Folder"), true );
03147 if ( dlg.exec() ) {
03148 dest = dlg.folder();
03149 }
03150 }
03151 }
03152 if ( dest ) {
03153 QPtrList<KMMsgBase> msgs;
03154 for( int i = 0; i < count(); ++i ) {
03155 KMMsgBase *msg = getMsgBase( i );
03156 if( !msg ) continue;
03157 if ( msg->UID() == 0 )
03158 msgs.append( msg );
03159 }
03160 KMCommand *command = new KMMoveCommand( dest, msgs );
03161 command->start();
03162 return command;
03163 }
03164 return 0;
03165 }
03166
03167 void KMFolderCachedImap::rescueUnsyncedMessagesAndDeleteFolder( KMFolder *folder, bool root )
03168 {
03169 kdDebug() << k_funcinfo << folder << " " << root << endl;
03170 if ( root )
03171 mToBeDeletedAfterRescue.append( folder );
03172 folder->open("cachedimap");
03173 KMFolderCachedImap* storage = dynamic_cast<KMFolderCachedImap*>( folder->storage() );
03174 if ( storage ) {
03175 KMCommand *command = storage->rescueUnsyncedMessages();
03176 if ( command ) {
03177 connect( command, SIGNAL(completed(KMCommand*)),
03178 SLOT(slotRescueDone(KMCommand*)) );
03179 ++mRescueCommandCount;
03180 } else {
03181
03182
03183 folder->close("cachedimap");
03184 }
03185 }
03186 if ( folder->child() ) {
03187 KMFolderNode *node = folder->child()->first();
03188 while (node) {
03189 if (!node->isDir() ) {
03190 KMFolder *subFolder = static_cast<KMFolder*>( node );
03191 rescueUnsyncedMessagesAndDeleteFolder( subFolder, false );
03192 }
03193 node = folder->child()->next();
03194 }
03195 }
03196 }
03197
03198 void KMFolderCachedImap::slotRescueDone(KMCommand * command)
03199 {
03200
03201 if ( command )
03202 --mRescueCommandCount;
03203 if ( mRescueCommandCount > 0 )
03204 return;
03205 for ( QValueList<KMFolder*>::ConstIterator it = mToBeDeletedAfterRescue.constBegin();
03206 it != mToBeDeletedAfterRescue.constEnd(); ++it ) {
03207 kmkernel->dimapFolderMgr()->remove( *it );
03208 }
03209 mToBeDeletedAfterRescue.clear();
03210 serverSyncInternal();
03211 }
03212
03213 void KMFolderCachedImap::slotRenameFolderFinished()
03214 {
03215
03216
03217
03218 open( "cachedimap" );
03219 serverSyncInternal();
03220 }
03221
03222 bool KMFolderCachedImap::canDeleteMessages() const
03223 {
03224 if ( isReadOnly() )
03225 return false;
03226 if ( mUserRightsState == KMail::ACLJobs::Ok && !(userRights() & ACLJobs::Delete) )
03227 return false;
03228 return true;
03229 }
03230
03231 bool KMFolderCachedImap::mailCheckInProgress() const
03232 {
03233 return mSyncState != SYNC_STATE_INITIAL;
03234 }
03235
03236 #include "kmfoldercachedimap.moc"