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