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