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