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