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