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