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