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