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