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 new messages"));
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
01967
01968
01969 newState( mProgress + (progressSpan * done) / total, QString::null );
01970 }
01971
01972 void KMFolderCachedImap::setAccount(KMAcctCachedImap *aAccount)
01973 {
01974 assert( aAccount->isA("KMAcctCachedImap") );
01975 mAccount = aAccount;
01976 if( imapPath()=="/" ) aAccount->setFolder( folder() );
01977
01978
01979 QString newName = mAccount->renamedFolder( imapPath() );
01980 if ( !newName.isEmpty() )
01981 folder()->setLabel( newName );
01982
01983 if( !folder() || !folder()->child() || !folder()->child()->count() ) return;
01984 for( KMFolderNode* node = folder()->child()->first(); node;
01985 node = folder()->child()->next() )
01986 if (!node->isDir())
01987 static_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage())->setAccount(aAccount);
01988 }
01989
01990 void KMFolderCachedImap::listNamespaces()
01991 {
01992 ImapAccountBase::ListType type = ImapAccountBase::List;
01993 if ( mAccount->onlySubscribedFolders() )
01994 type = ImapAccountBase::ListSubscribed;
01995
01996 kdDebug(5006) << "listNamespaces " << mNamespacesToList << endl;
01997 if ( mNamespacesToList.isEmpty() ) {
01998 mSyncState = SYNC_STATE_DELETE_SUBFOLDERS;
01999 mPersonalNamespacesCheckDone = true;
02000
02001 QStringList ns = mAccount->namespaces()[ImapAccountBase::OtherUsersNS];
02002 ns += mAccount->namespaces()[ImapAccountBase::SharedNS];
02003 mNamespacesToCheck = ns.count();
02004 for ( QStringList::Iterator it = ns.begin(); it != ns.end(); ++it )
02005 {
02006 if ( (*it).isEmpty() ) {
02007
02008 --mNamespacesToCheck;
02009 continue;
02010 }
02011 KMail::ListJob* job = new KMail::ListJob( mAccount, type, this, mAccount->addPathToNamespace( *it ) );
02012 job->setHonorLocalSubscription( true );
02013 connect( job, SIGNAL(receivedFolders(const QStringList&, const QStringList&,
02014 const QStringList&, const QStringList&, const ImapAccountBase::jobData&)),
02015 this, SLOT(slotCheckNamespace(const QStringList&, const QStringList&,
02016 const QStringList&, const QStringList&, const ImapAccountBase::jobData&)));
02017 job->start();
02018 }
02019 if ( mNamespacesToCheck == 0 ) {
02020 serverSyncInternal();
02021 }
02022 return;
02023 }
02024 mPersonalNamespacesCheckDone = false;
02025
02026 QString ns = mNamespacesToList.front();
02027 mNamespacesToList.pop_front();
02028
02029 mSyncState = SYNC_STATE_LIST_SUBFOLDERS2;
02030 newState( mProgress, i18n("Retrieving folders for namespace %1").arg(ns));
02031 KMail::ListJob* job = new KMail::ListJob( mAccount, type, this,
02032 mAccount->addPathToNamespace( ns ) );
02033 job->setNamespace( ns );
02034 job->setHonorLocalSubscription( true );
02035 connect( job, SIGNAL(receivedFolders(const QStringList&, const QStringList&,
02036 const QStringList&, const QStringList&, const ImapAccountBase::jobData&)),
02037 this, SLOT(slotListResult(const QStringList&, const QStringList&,
02038 const QStringList&, const QStringList&, const ImapAccountBase::jobData&)));
02039 job->start();
02040 }
02041
02042 void KMFolderCachedImap::slotCheckNamespace( const QStringList& subfolderNames,
02043 const QStringList& subfolderPaths,
02044 const QStringList& subfolderMimeTypes,
02045 const QStringList& subfolderAttributes,
02046 const ImapAccountBase::jobData& jobData )
02047 {
02048 Q_UNUSED( subfolderPaths );
02049 Q_UNUSED( subfolderMimeTypes );
02050 Q_UNUSED( subfolderAttributes );
02051 --mNamespacesToCheck;
02052 kdDebug(5006) << "slotCheckNamespace " << subfolderNames << ",remain=" <<
02053 mNamespacesToCheck << endl;
02054
02055
02056
02057 QString name = jobData.path.mid( 1, jobData.path.length()-2 );
02058 name.remove( mAccount->delimiterForNamespace( name ) );
02059 if ( name.isEmpty() ) {
02060
02061 kdWarning(5006) << "slotCheckNamespace: ignoring empty folder!" << endl;
02062 return;
02063 }
02064
02065 folder()->createChildFolder();
02066 KMFolderNode *node = 0;
02067 for ( node = folder()->child()->first(); node;
02068 node = folder()->child()->next())
02069 {
02070 if ( !node->isDir() && node->name() == name )
02071 break;
02072 }
02073 if ( !subfolderNames.isEmpty() ) {
02074 if ( node ) {
02075
02076 kdDebug(5006) << "found namespace folder " << name << endl;
02077 } else
02078 {
02079
02080 kdDebug(5006) << "create namespace folder " << name << endl;
02081 KMFolder* newFolder = folder()->child()->createFolder( name, false,
02082 KMFolderTypeCachedImap );
02083 if ( newFolder ) {
02084 KMFolderCachedImap *f = static_cast<KMFolderCachedImap*>( newFolder->storage() );
02085 f->setImapPath( mAccount->addPathToNamespace( name ) );
02086 f->setNoContent( true );
02087 f->setAccount( mAccount );
02088 f->close("cachedimap");
02089 kmkernel->dimapFolderMgr()->contentsChanged();
02090 }
02091 }
02092 } else {
02093 if ( node ) {
02094 kdDebug(5006) << "delete namespace folder " << name << endl;
02095 KMFolder* fld = static_cast<KMFolder*>(node);
02096 kmkernel->dimapFolderMgr()->remove( fld );
02097 }
02098 }
02099
02100 if ( mNamespacesToCheck == 0 ) {
02101
02102 serverSyncInternal();
02103 }
02104 }
02105
02106
02107
02108 bool KMFolderCachedImap::listDirectory()
02109 {
02110 if( !mAccount->slave() ) {
02111 resetSyncState();
02112 emit folderComplete( this, false );
02113 return false;
02114 }
02115 mSubfolderState = imapInProgress;
02116
02117
02118 ImapAccountBase::ListType type = ImapAccountBase::List;
02119 if ( mAccount->onlySubscribedFolders() )
02120 type = ImapAccountBase::ListSubscribed;
02121 KMail::ListJob* job = new KMail::ListJob( mAccount, type, this );
02122 job->setHonorLocalSubscription( true );
02123 connect( job, SIGNAL(receivedFolders(const QStringList&, const QStringList&,
02124 const QStringList&, const QStringList&, const ImapAccountBase::jobData&)),
02125 this, SLOT(slotListResult(const QStringList&, const QStringList&,
02126 const QStringList&, const QStringList&, const ImapAccountBase::jobData&)));
02127 job->start();
02128
02129 return true;
02130 }
02131
02132 void KMFolderCachedImap::slotListResult( const QStringList& folderNames,
02133 const QStringList& folderPaths,
02134 const QStringList& folderMimeTypes,
02135 const QStringList& folderAttributes,
02136 const ImapAccountBase::jobData& jobData )
02137 {
02138 Q_UNUSED( jobData );
02139
02140
02141 mSubfolderNames = folderNames;
02142 mSubfolderPaths = folderPaths;
02143 mSubfolderMimeTypes = folderMimeTypes;
02144 mSubfolderState = imapFinished;
02145 mSubfolderAttributes = folderAttributes;
02146
02147
02148 folder()->createChildFolder();
02149 KMFolderNode *node = folder()->child()->first();
02150 bool root = ( this == mAccount->rootFolder() );
02151
02152 QPtrList<KMFolder> toRemove;
02153 bool emptyList = ( root && mSubfolderNames.empty() );
02154 if ( !emptyList ) {
02155 while (node) {
02156 if (!node->isDir() ) {
02157 KMFolderCachedImap *f = static_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage());
02158
02159 if ( mSubfolderNames.findIndex(node->name()) == -1 ) {
02160 QString name = node->name();
02161
02162
02163 bool isInNamespace = ( jobData.curNamespace.isEmpty() ||
02164 jobData.curNamespace == mAccount->namespaceForFolder( f ) );
02165
02166 bool ignore = root && ( f->imapPath() == "/INBOX/" ||
02167 mAccount->isNamespaceFolder( name ) || !isInNamespace );
02168
02169
02170 if( !f->imapPath().isEmpty() && !ignore ) {
02171
02172
02173 toRemove.append( f->folder() );
02174 kdDebug(5006) << node->name() << " isn't on the server. It has an imapPath -> delete it locally" << endl;
02175 }
02176 } else {
02177
02178
02182 int index = mSubfolderNames.findIndex( node->name() );
02183 f->mFolderAttributes = folderAttributes[ index ];
02184 }
02185 } else {
02186
02187 }
02188 node = folder()->child()->next();
02189 }
02190 }
02191
02192 for ( KMFolder* doomed=toRemove.first(); doomed; doomed = toRemove.next() ) {
02193 rescueUnsyncedMessagesAndDeleteFolder( doomed );
02194 }
02195
02196 mProgress += 5;
02197
02198
02199 slotRescueDone( 0 );
02200 }
02201
02202
02203 void KMFolderCachedImap::listDirectory2()
02204 {
02205 QString path = folder()->path();
02206 kmkernel->dimapFolderMgr()->quiet(true);
02207
02208 bool root = ( this == mAccount->rootFolder() );
02209 if ( root && !mAccount->hasInbox() )
02210 {
02211 KMFolderCachedImap *f = 0;
02212 KMFolderNode *node;
02213
02214 for (node = folder()->child()->first(); node; node = folder()->child()->next())
02215 if (!node->isDir() && node->name() == "INBOX") break;
02216 if (node) {
02217 f = static_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage());
02218 } else {
02219 KMFolder* newFolder = folder()->child()->createFolder("INBOX", true, KMFolderTypeCachedImap);
02220 if ( newFolder ) {
02221 f = static_cast<KMFolderCachedImap*>(newFolder->storage());
02222 }
02223 }
02224 if ( f ) {
02225 f->setAccount( mAccount );
02226 f->setImapPath( "/INBOX/" );
02227 f->folder()->setLabel( i18n("inbox") );
02228 }
02229 if (!node) {
02230 if ( f )
02231 f->close("cachedimap");
02232 kmkernel->dimapFolderMgr()->contentsChanged();
02233 }
02234
02235 mAccount->setHasInbox( true );
02236 }
02237
02238 if ( root && !mSubfolderNames.isEmpty() ) {
02239 KMFolderCachedImap* parent =
02240 findParent( mSubfolderPaths.first(), mSubfolderNames.first() );
02241 if ( parent ) {
02242 kdDebug(5006) << "KMFolderCachedImap::listDirectory2 - pass listing to "
02243 << parent->label() << endl;
02244 mSubfolderNames.clear();
02245 }
02246 }
02247
02248
02249 QValueVector<int> foldersNewOnServer;
02250 for (uint i = 0; i < mSubfolderNames.count(); i++) {
02251
02252
02253 KMFolderCachedImap *f = 0;
02254 KMFolderNode *node = 0;
02255 for (node = folder()->child()->first(); node;
02256 node = folder()->child()->next())
02257 if (!node->isDir() && node->name() == mSubfolderNames[i]) break;
02258
02259 if (!node) {
02260
02261
02262 QString subfolderPath = mSubfolderPaths[i];
02263
02264
02265
02266 bool locallyDeleted = mAccount->isDeletedFolder( subfolderPath );
02267
02268
02269
02270 if ( !locallyDeleted && mAccount->isPreviouslyDeletedFolder( subfolderPath ) ) {
02271 locallyDeleted = KMessageBox::warningYesNo(
02272 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;
02273 }
02274
02275 if ( locallyDeleted ) {
02276 kdDebug(5006) << subfolderPath << " was deleted locally => delete on server." << endl;
02277 foldersForDeletionOnServer += mAccount->deletedFolderPaths( subfolderPath );
02278 } else {
02279 kdDebug(5006) << subfolderPath << " is a new folder on the server => create local cache" << endl;
02280 foldersNewOnServer.append( i );
02281 }
02282 } else {
02283 if( static_cast<KMFolder*>(node)->folderType() == KMFolderTypeCachedImap )
02284 f = dynamic_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage());
02285 if( f ) {
02286
02287
02288
02289 f->setAccount(mAccount);
02290 f->setNoContent(mSubfolderMimeTypes[i] == "inode/directory");
02291 f->setNoChildren(mSubfolderMimeTypes[i] == "message/digest");
02292 f->setImapPath(mSubfolderPaths[i]);
02293 }
02294 }
02295 }
02296
02297
02298
02299
02300
02301
02302
02303
02304
02305
02306
02307 if ( GlobalSettings::self()->showOnlyGroupwareFoldersForGroupwareAccount()
02308 && GlobalSettings::self()->theIMAPResourceAccount() == (int)mAccount->id()
02309 && mAccount->hasAnnotationSupport()
02310 && GlobalSettings::self()->theIMAPResourceEnabled()
02311 && !foldersNewOnServer.isEmpty() ) {
02312
02313 QStringList paths;
02314 for ( uint i = 0; i < foldersNewOnServer.count(); ++i )
02315 paths << mSubfolderPaths[ foldersNewOnServer[i] ];
02316
02317 AnnotationJobs::MultiUrlGetAnnotationJob* job =
02318 AnnotationJobs::multiUrlGetAnnotation( mAccount->slave(), mAccount->getUrl(), paths, KOLAB_FOLDERTYPE );
02319 ImapAccountBase::jobData jd( QString::null, folder() );
02320 jd.cancellable = true;
02321 mAccount->insertJob(job, jd);
02322 connect( job, SIGNAL(result(KIO::Job *)),
02323 SLOT(slotMultiUrlGetAnnotationResult(KIO::Job *)) );
02324
02325 } else {
02326 createFoldersNewOnServerAndFinishListing( foldersNewOnServer );
02327 }
02328 }
02329
02330 void KMFolderCachedImap::createFoldersNewOnServerAndFinishListing( const QValueVector<int> foldersNewOnServer )
02331 {
02332 for ( uint i = 0; i < foldersNewOnServer.count(); ++i ) {
02333 int idx = foldersNewOnServer[i];
02334 KMFolder* newFolder = folder()->child()->createFolder( mSubfolderNames[idx], false, KMFolderTypeCachedImap);
02335 if (newFolder) {
02336 KMFolderCachedImap *f = dynamic_cast<KMFolderCachedImap*>(newFolder->storage());
02337 kdDebug(5006) << " ####### Locally creating folder " << mSubfolderNames[idx] <<endl;
02338 f->close("cachedimap");
02339 f->setAccount(mAccount);
02340 f->mAnnotationFolderType = "FROMSERVER";
02341 f->setNoContent(mSubfolderMimeTypes[idx] == "inode/directory");
02342 f->setNoChildren(mSubfolderMimeTypes[idx] == "message/digest");
02343 f->setImapPath(mSubfolderPaths[idx]);
02344 f->mFolderAttributes = mSubfolderAttributes[idx];
02345 kdDebug(5006) << " ####### Attributes: " << f->mFolderAttributes <<endl;
02346
02347 kmkernel->dimapFolderMgr()->contentsChanged();
02348 } else {
02349 kdDebug(5006) << "can't create folder " << mSubfolderNames[idx] <<endl;
02350 }
02351 }
02352
02353 kmkernel->dimapFolderMgr()->quiet(false);
02354 emit listComplete(this);
02355 if ( !mPersonalNamespacesCheckDone ) {
02356
02357 mSyncState = SYNC_STATE_LIST_NAMESPACES;
02358 }
02359 serverSyncInternal();
02360 }
02361
02362
02363 KMFolderCachedImap* KMFolderCachedImap::findParent( const QString& path,
02364 const QString& name )
02365 {
02366 QString parent = path.left( path.length() - name.length() - 2 );
02367 if ( parent.length() > 1 )
02368 {
02369
02370 parent = parent.right( parent.length() - 1 );
02371 if ( parent != label() )
02372 {
02373 KMFolderNode *node = folder()->child()->first();
02374
02375 while ( node )
02376 {
02377 if ( node->name() == parent )
02378 {
02379 KMFolder* fld = static_cast<KMFolder*>(node);
02380 KMFolderCachedImap* imapFld =
02381 static_cast<KMFolderCachedImap*>( fld->storage() );
02382 return imapFld;
02383 }
02384 node = folder()->child()->next();
02385 }
02386 }
02387 }
02388 return 0;
02389 }
02390
02391 void KMFolderCachedImap::slotSubFolderComplete(KMFolderCachedImap* sub, bool success)
02392 {
02393 Q_UNUSED(sub);
02394
02395 if ( success ) {
02396 serverSyncInternal();
02397 }
02398 else
02399 {
02400
02401 if ( mCurrentSubfolder ) {
02402 Q_ASSERT( sub == mCurrentSubfolder );
02403 disconnectSubFolderSignals();
02404 }
02405
02406
02407
02408 mSubfoldersForSync.clear();
02409 mSyncState = SYNC_STATE_INITIAL;
02410 close("cachedimap");
02411 emit syncStateChanged();
02412 emit folderComplete( this, false );
02413 }
02414 }
02415
02416 void KMFolderCachedImap::slotSubFolderCloseToQuotaChanged()
02417 {
02418 if ( !mQuotaOnly ) {
02419 mSomeSubFolderCloseToQuotaChanged = true;
02420 }
02421 }
02422
02423 void KMFolderCachedImap::slotSimpleData(KIO::Job * job, const QByteArray & data)
02424 {
02425 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
02426 if (it == mAccount->jobsEnd()) return;
02427 QBuffer buff((*it).data);
02428 buff.open(IO_WriteOnly | IO_Append);
02429 buff.writeBlock(data.data(), data.size());
02430 buff.close();
02431 }
02432
02433 FolderJob*
02434 KMFolderCachedImap::doCreateJob( KMMessage *msg, FolderJob::JobType jt, KMFolder *folder,
02435 QString, const AttachmentStrategy* ) const
02436 {
02437 QPtrList<KMMessage> msgList;
02438 msgList.append( msg );
02439 CachedImapJob *job = new CachedImapJob( msgList, jt, folder? static_cast<KMFolderCachedImap*>( folder->storage() ):0 );
02440 job->setParentFolder( this );
02441 return job;
02442 }
02443
02444 FolderJob*
02445 KMFolderCachedImap::doCreateJob( QPtrList<KMMessage>& msgList, const QString& sets,
02446 FolderJob::JobType jt, KMFolder *folder ) const
02447 {
02448
02449 Q_UNUSED( sets );
02450 CachedImapJob *job = new CachedImapJob( msgList, jt, folder? static_cast<KMFolderCachedImap*>( folder->storage() ):0 );
02451 job->setParentFolder( this );
02452 return job;
02453 }
02454
02455 void
02456 KMFolderCachedImap::setUserRights( unsigned int userRights )
02457 {
02458 mUserRights = userRights;
02459 writeConfigKeysWhichShouldNotGetOverwrittenByReadConfig();
02460 }
02461
02462 void
02463 KMFolderCachedImap::slotReceivedUserRights( KMFolder* folder )
02464 {
02465 if ( folder->storage() == this ) {
02466 disconnect( mAccount, SIGNAL( receivedUserRights( KMFolder* ) ),
02467 this, SLOT( slotReceivedUserRights( KMFolder* ) ) );
02468 if ( mUserRights == 0 )
02469 mUserRights = -1;
02470 else
02471 setReadOnly( ( mUserRights & KMail::ACLJobs::Insert ) == 0 );
02472 mProgress += 5;
02473 serverSyncInternal();
02474 }
02475 }
02476
02477 void
02478 KMFolderCachedImap::setReadOnly( bool readOnly )
02479 {
02480 if ( readOnly != mReadOnly ) {
02481 mReadOnly = readOnly;
02482 emit readOnlyChanged( folder() );
02483 }
02484 }
02485
02486 void
02487 KMFolderCachedImap::slotReceivedACL( KMFolder* folder, KIO::Job*, const KMail::ACLList& aclList )
02488 {
02489 if ( folder->storage() == this ) {
02490 disconnect( mAccount, SIGNAL(receivedACL( KMFolder*, KIO::Job*, const KMail::ACLList& )),
02491 this, SLOT(slotReceivedACL( KMFolder*, KIO::Job*, const KMail::ACLList& )) );
02492 mACLList = aclList;
02493 serverSyncInternal();
02494 }
02495 }
02496
02497 void
02498 KMFolderCachedImap::slotStorageQuotaResult( const QuotaInfo& info )
02499 {
02500 setQuotaInfo( info );
02501 }
02502
02503 void KMFolderCachedImap::setQuotaInfo( const QuotaInfo & info )
02504 {
02505 if ( info != mQuotaInfo ) {
02506 const bool wasCloseToQuota = isCloseToQuota();
02507 mQuotaInfo = info;
02508 writeConfigKeysWhichShouldNotGetOverwrittenByReadConfig();
02509 if ( wasCloseToQuota != isCloseToQuota() ) {
02510 emit closeToQuotaChanged();
02511 }
02512 emit folderSizeChanged();
02513 }
02514 }
02515
02516 void
02517 KMFolderCachedImap::setACLList( const ACLList& arr )
02518 {
02519 mACLList = arr;
02520 }
02521
02522 void
02523 KMFolderCachedImap::slotMultiSetACLResult(KIO::Job *job)
02524 {
02525 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
02526 if ( it == mAccount->jobsEnd() ) return;
02527 if ( (*it).parent != folder() ) return;
02528
02529 if ( job->error() )
02530
02531
02532 job->showErrorDialog();
02533 else
02534 kmkernel->iCalIface().addFolderChange( folder(), KMailICalIfaceImpl::ACL );
02535
02536 if (mAccount->slave()) mAccount->removeJob(job);
02537 serverSyncInternal();
02538 }
02539
02540 void
02541 KMFolderCachedImap::slotACLChanged( const QString& userId, int permissions )
02542 {
02543
02544
02545 for( ACLList::Iterator it = mACLList.begin(); it != mACLList.end(); ++it ) {
02546 if ( (*it).userId == userId && (*it).permissions == permissions ) {
02547 if ( permissions == -1 )
02548 mACLList.erase( it );
02549 else
02550 (*it).changed = false;
02551 return;
02552 }
02553 }
02554 }
02555
02556
02557 void KMFolderCachedImap::resetSyncState()
02558 {
02559 if ( mSyncState == SYNC_STATE_INITIAL ) return;
02560 mSubfoldersForSync.clear();
02561 mSyncState = SYNC_STATE_INITIAL;
02562 close("cachedimap");
02563
02564 KPIM::ProgressItem *progressItem = mAccount->mailCheckProgressItem();
02565 QString str = i18n("Aborted");
02566 if (progressItem)
02567 progressItem->setStatus( str );
02568 emit statusMsg( str );
02569 emit syncStateChanged();
02570 }
02571
02572 void KMFolderCachedImap::slotIncreaseProgress()
02573 {
02574 mProgress += 5;
02575 }
02576
02577 void KMFolderCachedImap::newState( int progress, const QString& syncStatus )
02578 {
02579
02580 KPIM::ProgressItem *progressItem = mAccount->mailCheckProgressItem();
02581 if( progressItem )
02582 progressItem->setCompletedItems( progress );
02583 if ( !syncStatus.isEmpty() ) {
02584 QString str;
02585
02586 if ( mAccount->imapFolder() == this )
02587 str = syncStatus;
02588 else
02589 str = QString( "%1: %2" ).arg( label() ).arg( syncStatus );
02590 if( progressItem )
02591 progressItem->setStatus( str );
02592 emit statusMsg( str );
02593 }
02594 if( progressItem )
02595 progressItem->updateProgress();
02596 }
02597
02598 void KMFolderCachedImap::setSubfolderState( imapState state )
02599 {
02600 mSubfolderState = state;
02601 if ( state == imapNoInformation && folder()->child() )
02602 {
02603
02604 KMFolderNode* node;
02605 QPtrListIterator<KMFolderNode> it( *folder()->child() );
02606 for ( ; (node = it.current()); )
02607 {
02608 ++it;
02609 if (node->isDir()) continue;
02610 KMFolder *folder = static_cast<KMFolder*>(node);
02611 static_cast<KMFolderCachedImap*>(folder->storage())->setSubfolderState( state );
02612 }
02613 }
02614 }
02615
02616 void KMFolderCachedImap::setImapPath(const QString &path)
02617 {
02618 mImapPath = path;
02619 }
02620
02621 static bool isFolderTypeKnownToUs( const QString &type )
02622 {
02623 for ( uint i = 0 ; i <= ContentsTypeLast; ++i ) {
02624 FolderContentsType contentsType = static_cast<KMail::FolderContentsType>( i );
02625 if ( type == KMailICalIfaceImpl::annotationForContentsType( contentsType ) )
02626 return true;
02627 }
02628 return false;
02629 }
02630
02631
02632
02633
02634
02635
02636 void KMFolderCachedImap::updateAnnotationFolderType()
02637 {
02638 QString oldType = mAnnotationFolderType;
02639 QString oldSubType;
02640 int dot = oldType.find( '.' );
02641 if ( dot != -1 ) {
02642 oldType.truncate( dot );
02643 oldSubType = mAnnotationFolderType.mid( dot + 1 );
02644 }
02645
02646 QString newType, newSubType;
02647
02648 if ( kmkernel->iCalIface().storageFormat( folder() ) == KMailICalIfaceImpl::StorageXML ) {
02649 newType = KMailICalIfaceImpl::annotationForContentsType( mContentsType );
02650 if ( kmkernel->iCalIface().isStandardResourceFolder( folder() ) )
02651 newSubType = "default";
02652 else if ( oldSubType != "default" )
02653 newSubType = oldSubType;
02654 }
02655
02656
02657
02658
02659 const bool changingTypeAllowed = isFolderTypeKnownToUs( oldType ) ||
02660 ( mContentsType != ContentsTypeMail );
02661
02662
02663 if ( ( newType != oldType || newSubType != oldSubType ) && changingTypeAllowed ) {
02664 mAnnotationFolderType = newType + ( newSubType.isEmpty() ? QString::null : "."+newSubType );
02665 mAnnotationFolderTypeChanged = true;
02666 kdDebug(5006) << mImapPath << ": updateAnnotationFolderType: '" << mAnnotationFolderType << "', was (" << oldType << " " << oldSubType << ") => mAnnotationFolderTypeChanged set to TRUE" << endl;
02667 }
02668
02669 writeConfigKeysWhichShouldNotGetOverwrittenByReadConfig();
02670 }
02671
02672 void KMFolderCachedImap::setIncidencesFor( IncidencesFor incfor )
02673 {
02674 if ( mIncidencesFor != incfor ) {
02675 mIncidencesFor = incfor;
02676 mIncidencesForChanged = true;
02677 }
02678 }
02679
02680 void KMFolderCachedImap::setSharedSeenFlags(bool b)
02681 {
02682 if ( mSharedSeenFlags != b ) {
02683 mSharedSeenFlags = b;
02684 mSharedSeenFlagsChanged = true;
02685 }
02686 }
02687
02688 void KMFolderCachedImap::slotAnnotationResult(const QString& entry, const QString& value, bool found)
02689 {
02690 if ( entry == KOLAB_FOLDERTYPE ) {
02691
02692
02693
02694
02695
02696 if ( found ) {
02697 QString type = value;
02698 QString subtype;
02699 int dot = value.find( '.' );
02700 if ( dot != -1 ) {
02701 type.truncate( dot );
02702 subtype = value.mid( dot + 1 );
02703 }
02704 bool foundKnownType = false;
02705 for ( uint i = 0 ; i <= ContentsTypeLast; ++i ) {
02706 FolderContentsType contentsType = static_cast<KMail::FolderContentsType>( i );
02707 if ( type == KMailICalIfaceImpl::annotationForContentsType( contentsType ) ) {
02708
02709
02710 if ( contentsType != ContentsTypeMail )
02711 kmkernel->iCalIface().setStorageFormat( folder(), KMailICalIfaceImpl::StorageXML );
02712 mAnnotationFolderType = value;
02713 if ( folder()->parent()->owner()->idString() != GlobalSettings::self()->theIMAPResourceFolderParent()
02714 && GlobalSettings::self()->theIMAPResourceEnabled()
02715 && subtype == "default" ) {
02716
02717
02718 mAnnotationFolderType = type;
02719 kdDebug(5006) << mImapPath << ": slotGetAnnotationResult: parent folder is " << folder()->parent()->owner()->idString() << " => truncating annotation to " << value << endl;
02720 }
02721 setContentsType( contentsType );
02722 mAnnotationFolderTypeChanged = false;
02723 foundKnownType = true;
02724
02725
02726
02727
02728
02729 if ( contentsType != ContentsTypeMail )
02730 markUnreadAsRead();
02731
02732 break;
02733 }
02734 }
02735 if ( !foundKnownType ) {
02736
02737
02738
02739
02740 mAnnotationFolderTypeChanged = false;
02741 mAnnotationFolderType = value;
02742 setContentsType( ContentsTypeMail );
02743 }
02744
02745
02746 writeConfigKeysWhichShouldNotGetOverwrittenByReadConfig();
02747
02748 }
02749 else if ( !mReadOnly ) {
02750
02751
02752 mAnnotationFolderTypeChanged = true;
02753 }
02754 } else if ( entry == KOLAB_INCIDENCESFOR ) {
02755 if ( found ) {
02756 mIncidencesFor = incidencesForFromString( value );
02757 Q_ASSERT( mIncidencesForChanged == false );
02758 }
02759 } else if ( entry == KOLAB_SHAREDSEEN ) {
02760 if ( found ) {
02761 mSharedSeenFlags = value == "true";
02762 }
02763 }
02764 }
02765
02766 void KMFolderCachedImap::slotGetAnnotationResult( KIO::Job* job )
02767 {
02768 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
02769 Q_ASSERT( it != mAccount->jobsEnd() );
02770 if ( it == mAccount->jobsEnd() ) return;
02771 Q_ASSERT( (*it).parent == folder() );
02772 if ( (*it).parent != folder() ) return;
02773
02774 AnnotationJobs::GetAnnotationJob* annjob = static_cast<AnnotationJobs::GetAnnotationJob *>( job );
02775 if ( annjob->error() ) {
02776 if ( job->error() == KIO::ERR_UNSUPPORTED_ACTION ) {
02777
02778 if ( GlobalSettings::self()->theIMAPResourceStorageFormat() == GlobalSettings::EnumTheIMAPResourceStorageFormat::XML
02779 && (uint)GlobalSettings::self()->theIMAPResourceAccount() == mAccount->id() )
02780 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() ) );
02781 mAccount->setHasNoAnnotationSupport();
02782 }
02783 else
02784 kdWarning(5006) << "slotGetAnnotationResult: " << job->errorString() << endl;
02785 }
02786
02787 if (mAccount->slave()) mAccount->removeJob(job);
02788 mProgress += 2;
02789 serverSyncInternal();
02790 }
02791
02792 void KMFolderCachedImap::slotMultiUrlGetAnnotationResult( KIO::Job* job )
02793 {
02794 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
02795 Q_ASSERT( it != mAccount->jobsEnd() );
02796 if ( it == mAccount->jobsEnd() ) return;
02797 Q_ASSERT( (*it).parent == folder() );
02798 if ( (*it).parent != folder() ) return;
02799
02800 QValueVector<int> folders;
02801 AnnotationJobs::MultiUrlGetAnnotationJob* annjob
02802 = static_cast<AnnotationJobs::MultiUrlGetAnnotationJob *>( job );
02803 if ( annjob->error() ) {
02804 if ( job->error() == KIO::ERR_UNSUPPORTED_ACTION ) {
02805
02806 if ( GlobalSettings::self()->theIMAPResourceStorageFormat() == GlobalSettings::EnumTheIMAPResourceStorageFormat::XML
02807 && (uint)GlobalSettings::self()->theIMAPResourceAccount() == mAccount->id() )
02808 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() ) );
02809 mAccount->setHasNoAnnotationSupport();
02810 }
02811 else
02812 kdWarning(5006) << "slotGetMultiUrlAnnotationResult: " << job->errorString() << endl;
02813 } else {
02814
02815 QMap<QString, QString> annotations = annjob->annotations();
02816 QMap<QString, QString>::Iterator it = annotations.begin();
02817 for ( ; it != annotations.end(); ++it ) {
02818 const QString folderPath = it.key();
02819 const QString annotation = it.data();
02820 kdDebug(5006) << k_funcinfo << "Folder: " << folderPath << " has type: " << annotation << endl;
02821
02822 QString type(annotation);
02823 int dot = annotation.find( '.' );
02824 if ( dot != -1 ) type.truncate( dot );
02825 type = type.simplifyWhiteSpace();
02826
02827 const int idx = mSubfolderPaths.findIndex( folderPath );
02828 const bool isNoContent = mSubfolderMimeTypes[idx] == "inode/directory";
02829 if ( ( isNoContent && type.isEmpty() )
02830 || ( !type.isEmpty() && type != KMailICalIfaceImpl::annotationForContentsType( ContentsTypeMail ) ) ) {
02831 folders.append( idx );
02832 kdDebug(5006) << k_funcinfo << " subscribing to: " << folderPath << endl;
02833 } else {
02834 kdDebug(5006) << k_funcinfo << " automatically unsubscribing from: " << folderPath << endl;
02835 mAccount->changeLocalSubscription( folderPath, false );
02836 }
02837 }
02838 }
02839
02840 if (mAccount->slave()) mAccount->removeJob(job);
02841 createFoldersNewOnServerAndFinishListing( folders );
02842 }
02843
02844 void KMFolderCachedImap::slotQuotaResult( KIO::Job* job )
02845 {
02846 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
02847 Q_ASSERT( it != mAccount->jobsEnd() );
02848 if ( it == mAccount->jobsEnd() ) return;
02849 Q_ASSERT( (*it).parent == folder() );
02850 if ( (*it).parent != folder() ) return;
02851
02852 QuotaJobs::GetStorageQuotaJob* quotajob = static_cast<QuotaJobs::GetStorageQuotaJob *>( job );
02853 QuotaInfo empty;
02854 if ( quotajob->error() ) {
02855 if ( job->error() == KIO::ERR_UNSUPPORTED_ACTION ) {
02856
02857 mAccount->setHasNoQuotaSupport();
02858 setQuotaInfo( empty );
02859 }
02860 else
02861 kdWarning(5006) << "slotGetQuotaResult: " << job->errorString() << endl;
02862 }
02863
02864 if (mAccount->slave()) mAccount->removeJob(job);
02865 mProgress += 2;
02866 serverSyncInternal();
02867 }
02868
02869 void
02870 KMFolderCachedImap::slotAnnotationChanged( const QString& entry, const QString& attribute, const QString& value )
02871 {
02872 Q_UNUSED( attribute );
02873 Q_UNUSED( value );
02874
02875 if ( entry == KOLAB_FOLDERTYPE )
02876 mAnnotationFolderTypeChanged = false;
02877 else if ( entry == KOLAB_INCIDENCESFOR ) {
02878 mIncidencesForChanged = false;
02879
02880
02881 kmkernel->iCalIface().addFolderChange( folder(), KMailICalIfaceImpl::ACL );
02882 } else if ( entry == KOLAB_SHAREDSEEN ) {
02883 mSharedSeenFlagsChanged = false;
02884 }
02885 }
02886
02887 void KMFolderCachedImap::slotTestAnnotationResult(KIO::Job *job)
02888 {
02889 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
02890 Q_ASSERT( it != mAccount->jobsEnd() );
02891 if ( it == mAccount->jobsEnd() ) return;
02892 Q_ASSERT( (*it).parent == folder() );
02893 if ( (*it).parent != folder() ) return;
02894
02895 mAccount->setAnnotationCheckPassed( true );
02896 if ( job->error() ) {
02897 kdDebug(5006) << "Test Annotation was not passed, disabling annotation support" << endl;
02898 mAccount->setHasNoAnnotationSupport( );
02899 } else {
02900 kdDebug(5006) << "Test Annotation was passed OK" << endl;
02901 }
02902 if (mAccount->slave()) mAccount->removeJob(job);
02903 serverSyncInternal();
02904 }
02905
02906 void
02907 KMFolderCachedImap::slotSetAnnotationResult(KIO::Job *job)
02908 {
02909 KMAcctCachedImap::JobIterator it = mAccount->findJob(job);
02910 if ( it == mAccount->jobsEnd() ) return;
02911 if ( (*it).parent != folder() ) return;
02912
02913 bool cont = true;
02914 if ( job->error() ) {
02915
02916 if ( job->error() == KIO::ERR_UNSUPPORTED_ACTION && contentsType() == ContentsTypeMail ) {
02917 if (mAccount->slave()) mAccount->removeJob(job);
02918 } else {
02919 cont = mAccount->handleJobError( job, i18n( "Error while setting annotation: " ) + '\n' );
02920 }
02921 } else {
02922 if (mAccount->slave()) mAccount->removeJob(job);
02923 }
02924 if ( cont )
02925 serverSyncInternal();
02926 }
02927
02928 void KMFolderCachedImap::slotUpdateLastUid()
02929 {
02930 if( mTentativeHighestUid != 0 ) {
02931
02932
02933
02934
02935
02936
02937
02938
02939
02940
02941
02942 bool sane = count() == 0;
02943
02944 for (int i=0;i<count(); i++ ) {
02945 ulong uid = getMsgBase(i)->UID();
02946 if ( uid > mTentativeHighestUid && uid > lastUid() ) {
02947 kdWarning(5006) << "DANGER: Either the server listed a wrong highest uid, "
02948 "or we parsed it wrong. Send email to adam@kde.org, please, and include this log." << endl;
02949 kdWarning(5006) << "uid: " << uid << " mTentativeHighestUid: " << mTentativeHighestUid << endl;
02950 assert( false );
02951 break;
02952 } else {
02953 sane = true;
02954 }
02955 }
02956 if (sane) {
02957 #if MAIL_LOSS_DEBUGGING
02958 kdDebug(5006) << "Tentative highest UID test was sane, writing out: " << mTentativeHighestUid << endl;
02959 #endif
02960 setLastUid( mTentativeHighestUid );
02961 }
02962 }
02963 mTentativeHighestUid = 0;
02964 }
02965
02966 bool KMFolderCachedImap::isMoveable() const
02967 {
02968 return ( hasChildren() == HasNoChildren &&
02969 !folder()->isSystemFolder() ) ? true : false;
02970 }
02971
02972 void KMFolderCachedImap::slotFolderDeletionOnServerFinished()
02973 {
02974 for ( QStringList::const_iterator it = foldersForDeletionOnServer.constBegin();
02975 it != foldersForDeletionOnServer.constEnd(); ++it ) {
02976 KURL url( mAccount->getUrl() );
02977 url.setPath( *it );
02978 kmkernel->iCalIface().folderDeletedOnServer( url );
02979 }
02980 serverSyncInternal();
02981 }
02982
02983 int KMFolderCachedImap::createIndexFromContentsRecursive()
02984 {
02985 if ( !folder() || !folder()->child() )
02986 return 0;
02987
02988 KMFolderNode *node = 0;
02989 for( QPtrListIterator<KMFolderNode> it( *folder()->child() ); (node = it.current()); ++it ) {
02990 if( !node->isDir() ) {
02991 KMFolderCachedImap* storage = static_cast<KMFolderCachedImap*>(static_cast<KMFolder*>(node)->storage());
02992 kdDebug() << k_funcinfo << "Re-indexing: " << storage->folder()->label() << endl;
02993 int rv = storage->createIndexFromContentsRecursive();
02994 if ( rv > 0 )
02995 return rv;
02996 }
02997 }
02998
02999 return createIndexFromContents();
03000 }
03001
03002 void KMFolderCachedImap::setAlarmsBlocked( bool blocked )
03003 {
03004 mAlarmsBlocked = blocked;
03005 }
03006
03007 bool KMFolderCachedImap::alarmsBlocked() const
03008 {
03009 return mAlarmsBlocked;
03010 }
03011
03012 bool KMFolderCachedImap::isCloseToQuota() const
03013 {
03014 bool closeToQuota = false;
03015 if ( mQuotaInfo.isValid() && mQuotaInfo.max().toInt() > 0 ) {
03016 const int ratio = mQuotaInfo.current().toInt() * 100 / mQuotaInfo.max().toInt();
03017
03018 closeToQuota = ( ratio > 0 && ratio >= GlobalSettings::closeToQuotaThreshold() );
03019 }
03020
03021 return closeToQuota;
03022 }
03023
03024 KMCommand* KMFolderCachedImap::rescueUnsyncedMessages()
03025 {
03026 QValueList<unsigned long> newMsgs = findNewMessages();
03027 kdDebug() << k_funcinfo << newMsgs << " of " << count() << endl;
03028 if ( newMsgs.isEmpty() )
03029 return 0;
03030 KMFolder *dest = 0;
03031 bool manualMove = true;
03032 while ( GlobalSettings::autoLostFoundMove() ) {
03033
03034 KMFolder *inboxFolder = kmkernel->findFolderById( QString(".%1.directory/INBOX").arg( account()->id() ) );
03035 if ( !inboxFolder ) {
03036 kdWarning(5006) << k_funcinfo << "inbox not found!" << endl;
03037 break;
03038 }
03039 KMFolderDir *inboxDir = inboxFolder->child();
03040 if ( !inboxDir && !inboxFolder->storage() )
03041 break;
03042 assert( inboxFolder->storage()->folderType() == KMFolderTypeCachedImap );
03043
03044
03045 KMFolderNode *node;
03046 KMFolder *lfFolder = 0;
03047 if ( !(node = inboxDir->hasNamedFolder( i18n("lost+found") )) ) {
03048 kdDebug(5006) << k_funcinfo << "creating lost+found folder" << endl;
03049 KMFolder* folder = kmkernel->dimapFolderMgr()->createFolder(
03050 i18n("lost+found"), false, KMFolderTypeCachedImap, inboxDir );
03051 if ( !folder || !folder->storage() )
03052 break;
03053 static_cast<KMFolderCachedImap*>( folder->storage() )->initializeFrom(
03054 static_cast<KMFolderCachedImap*>( inboxFolder->storage() ) );
03055 folder->storage()->setContentsType( KMail::ContentsTypeMail );
03056 folder->storage()->writeConfig();
03057 lfFolder = folder;
03058 } else {
03059 kdDebug(5006) << k_funcinfo << "found lost+found folder" << endl;
03060 lfFolder = dynamic_cast<KMFolder*>( node );
03061 }
03062 if ( !lfFolder || !lfFolder->createChildFolder() || !lfFolder->storage() )
03063 break;
03064
03065
03066 QDate today = QDate::currentDate();
03067 QString baseName = folder()->label() + "-" + QString::number( today.year() )
03068 + (today.month() < 10 ? "0" : "" ) + QString::number( today.month() )
03069 + (today.day() < 10 ? "0" : "" ) + QString::number( today.day() );
03070 QString name = baseName;
03071 int suffix = 0;
03072 while ( (node = lfFolder->child()->hasNamedFolder( name )) ) {
03073 ++suffix;
03074 name = baseName + '-' + QString::number( suffix );
03075 }
03076 kdDebug(5006) << k_funcinfo << "creating lost+found folder " << name << endl;
03077 dest = kmkernel->dimapFolderMgr()->createFolder( name, false, KMFolderTypeCachedImap, lfFolder->child() );
03078 if ( !dest || !dest->storage() )
03079 break;
03080 static_cast<KMFolderCachedImap*>( dest->storage() )->initializeFrom(
03081 static_cast<KMFolderCachedImap*>( lfFolder->storage() ) );
03082 dest->storage()->setContentsType( contentsType() );
03083 dest->storage()->writeConfig();
03084
03085 KMessageBox::sorry( 0, i18n("<p>There are new messages in folder <b>%1</b>, which "
03086 "have not been uploaded to the server yet, but the folder has been deleted "
03087 "on the server or you do not "
03088 "have sufficient access rights on the folder to upload them.</p>"
03089 "<p>All affected messages will therefore be moved to <b>%2</b> "
03090 "to avoid data loss.</p>").arg( folder()->prettyURL() ).arg( dest->prettyURL() ),
03091 i18n("Insufficient access rights") );
03092 manualMove = false;
03093 break;
03094 }
03095
03096 if ( manualMove ) {
03097 const QString msg ( i18n( "<p>There are new messages in this folder (%1), which "
03098 "have not been uploaded to the server yet, but the folder has been deleted "
03099 "on the server or you do not "
03100 "have sufficient access rights on the folder now to upload them. "
03101 "Please contact your administrator to allow upload of new messages "
03102 "to you, or move them out of this folder.</p> "
03103 "<p>Do you want to move these messages to another folder now?</p>").arg( folder()->prettyURL() ) );
03104 if ( KMessageBox::warningYesNo( 0, msg, QString::null, i18n("Move"), i18n("Do Not Move") ) == KMessageBox::Yes ) {
03105 KMail::KMFolderSelDlg dlg( kmkernel->getKMMainWidget(),
03106 i18n("Move Messages to Folder"), true );
03107 if ( dlg.exec() ) {
03108 dest = dlg.folder();
03109 }
03110 }
03111 }
03112 if ( dest ) {
03113 QPtrList<KMMsgBase> msgs;
03114 for( int i = 0; i < count(); ++i ) {
03115 KMMsgBase *msg = getMsgBase( i );
03116 if( !msg ) continue;
03117 if ( msg->UID() == 0 )
03118 msgs.append( msg );
03119 }
03120 KMCommand *command = new KMMoveCommand( dest, msgs );
03121 command->start();
03122 return command;
03123 }
03124 return 0;
03125 }
03126
03127 void KMFolderCachedImap::rescueUnsyncedMessagesAndDeleteFolder( KMFolder *folder, bool root )
03128 {
03129 kdDebug() << k_funcinfo << folder << " " << root << endl;
03130 if ( root )
03131 mToBeDeletedAfterRescue.append( folder );
03132 folder->open("cachedimap");
03133 KMFolderCachedImap* storage = dynamic_cast<KMFolderCachedImap*>( folder->storage() );
03134 if ( storage ) {
03135 KMCommand *command = storage->rescueUnsyncedMessages();
03136 if ( command ) {
03137 connect( command, SIGNAL(completed(KMCommand*)),
03138 SLOT(slotRescueDone(KMCommand*)) );
03139 ++mRescueCommandCount;
03140 } else {
03141
03142
03143 folder->close("cachedimap");
03144 }
03145 }
03146 if ( folder->child() ) {
03147 KMFolderNode *node = folder->child()->first();
03148 while (node) {
03149 if (!node->isDir() ) {
03150 KMFolder *subFolder = static_cast<KMFolder*>( node );
03151 rescueUnsyncedMessagesAndDeleteFolder( subFolder, false );
03152 }
03153 node = folder->child()->next();
03154 }
03155 }
03156 }
03157
03158 void KMFolderCachedImap::slotRescueDone(KMCommand * command)
03159 {
03160
03161 if ( command )
03162 --mRescueCommandCount;
03163 if ( mRescueCommandCount > 0 )
03164 return;
03165 for ( QValueList<KMFolder*>::ConstIterator it = mToBeDeletedAfterRescue.constBegin();
03166 it != mToBeDeletedAfterRescue.constEnd(); ++it ) {
03167 kmkernel->dimapFolderMgr()->remove( *it );
03168 }
03169 mToBeDeletedAfterRescue.clear();
03170 serverSyncInternal();
03171 }
03172
03173 void KMFolderCachedImap::slotRenameFolderFinished()
03174 {
03175
03176
03177
03178 open( "cachedimap" );
03179 serverSyncInternal();
03180 }
03181
03182 bool KMFolderCachedImap::canDeleteMessages() const
03183 {
03184 if ( isReadOnly() )
03185 return false;
03186 if ( userRights() > 0 && !(userRights() & ACLJobs::Delete) )
03187 return false;
03188 return true;
03189 }
03190
03191 bool KMFolderCachedImap::mailCheckInProgress() const
03192 {
03193 return mSyncState != SYNC_STATE_INITIAL;
03194 }
03195
03196 #include "kmfoldercachedimap.moc"