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