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