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