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