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