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