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